### Run File Assistant Example Source: https://github.com/cangjiepl/cangjiemagic/blob/dev/src/examples/file_assistant/README.md Execute the file assistant example from your terminal. Ensure all prerequisites and configurations are met before running. ```bash cjpm run --name magic.examples.file_assistant ``` -------------------------------- ### Command Line Assistant Agent Example Source: https://github.com/cangjiepl/cangjiemagic/blob/dev/docs/tutorial.md An example of a command-line assistant agent that uses the 'react' executor and a tool to fetch help documentation. It demonstrates how to define a prompt and a tool for interacting with command-line utilities. ```cangjie @agent[executor: "react"] class CJCAgent { @prompt( """ 你是一个 CJC 命令行助理。 你帮助用户根据他们的问题生成命令行。 """ ) @tool[description: "获取 CJC 的使用手册"] private func getManual(): String { let subProcess: SubProcess = Process.start( "cjc", ["--help"], stdOut: ProcessRedirect.Pipe ) let strReader: StringReader = StringReader(subProcess.stdOut) let result = strReader.readToEnd().trimAscii() return result } } let agent = CJCAgent() let result = agent.chat("编译一个文件到 ARM 平台") ``` -------------------------------- ### Run Markdown Q&A Example Source: https://github.com/cangjiepl/cangjiemagic/blob/dev/src/examples/markdown_qa/README.md Execute the Magic RAG Markdown Q&A example using the cjpm command. Ensure you have configured your API key first. ```bash cjpm run --name magic.examples.markdown_qa ``` -------------------------------- ### Global Event Handling Setup Source: https://context7.com/cangjiepl/cangjiemagic/llms.txt Configure global event handlers using `EventHandlerManager.global.addHandler` to capture events across all agents. This example sets up handlers for `ToolCallStartEvent` and `AgentEndEvent` for logging purposes. ```cangjie // 全局日志处理器 func setupGlobal() { EventHandlerManager.global.addHandler({ evt: ToolCallStartEvent => println("[全局日志] 工具调用: ${evt.toolRequest.name}") return EventResponse.Continue }) EventHandlerManager.global.addHandler({ evt: AgentEndEvent => println("[全局日志] Agent 执行完毕") return EventResponse.Continue }) } ``` -------------------------------- ### Run API Document Generator Example Source: https://github.com/cangjiepl/cangjiemagic/blob/dev/src/examples/doc_generator/README.md Execute the API document generator example using the Cangjie package manager. Ensure your large model API key is configured. The generated documentation will be saved in the 'temp-docs' directory. ```bash cjpm run --name magic.examples.doc_generator ``` -------------------------------- ### BaseAgent Initialization Example Source: https://github.com/cangjiepl/cangjiemagic/blob/dev/docs/tutorial.md Shows how to create and configure an agent using the BaseAgent class, setting its system prompt, model, and tools. ```cangjie let agent= BaseAgent() agent.systemPrompt = "New system prompt ..." agent.model = ModelManager.createChatModel("ollama:phi3") agent.toolManager.addTool(fooTool) ``` -------------------------------- ### DispatchAgent Initialization Example Source: https://github.com/cangjiepl/cangjiemagic/blob/dev/docs/tutorial.md Illustrates the initialization of a DispatchAgent for task distribution in a master-slave collaboration model. ```cangjie let group = DiapatchAgent(model: "deepseek:deepseek-chat") <=[ FooAgent(), BarAgent(), ... ] ``` -------------------------------- ### Agent Integration Example Source: https://github.com/cangjiepl/cangjiemagic/blob/dev/docs/tutorial.md Shows how to integrate a SemanticMap as a retriever into an agent. ```APIDOC ## Agent Integration Example ### Description This example demonstrates how to use the `asRetriever()` method of `SemanticMap` to obtain a retriever object and assign it to an agent's retriever property. Note that currently, the vector database can only be used in a `Static` mode. ### Code ```cangjie let agent = FooAgent() agent.retriever = smap.asRetriever() ``` ``` -------------------------------- ### Usage Example Source: https://github.com/cangjiepl/cangjiemagic/blob/dev/docs/tutorial.md Demonstrates how to use SemanticMap with InMemoryVectorDatabase and perform a search operation. ```APIDOC ## Usage Example ### Description This example shows how to instantiate `SemanticMap` with `InMemoryVectorDatabase`, add key-value pairs, perform a semantic search, and print the results. ### Code ```cangjie import magic.rag.vdb.* main() { let smap = SemanticMap(vectorDB: InMemoryVectorDatabase()) smap.put("前往上海", "Plan A") smap.put("吃饭", "Plan B") smap.put("前往北京", "Plan C") smap.put("睡觉", "Plan D") let c = smap.search("前往上海", number: 2) println(c) } ``` ``` -------------------------------- ### Interceptor Usage Example Source: https://github.com/cangjiepl/cangjiemagic/blob/dev/docs/tutorial.md Demonstrates how to set up an interceptor on an agent to handle requests periodically. ```cangjie let ag1 = Foo() let ag2 = Bar() ag1.interceptor = Interceptor(ag2, mode: InterceoptorMode.Periodic(2)) ag1.chat("msg 1") ag1.chat("msg 2") ag1.chat("msg 3") // ag2 will handle with this request message ``` -------------------------------- ### Install Cangjie Magic Source: https://context7.com/cangjiepl/cangjiemagic/llms.txt Clone the repository and add it as a dependency in your project's cjpm.toml file. Use 'cjpm run' to execute CLI programs. ```bash # 克隆源代码(通用版) git clone https://gitcode.com/Cangjie-TPC/CangjieMagic.git -b dev # 在项目的 cjpm.toml 中添加依赖 # [dependencies] # magic = { path = "" } # 运行项目(CLI 程序必须使用此命令) cjpm run --name ``` -------------------------------- ### ToolAgent Usage Example Source: https://github.com/cangjiepl/cangjiemagic/blob/dev/docs/tutorial.md Demonstrates using ToolAgent in a pipeline to execute a function directly for responses, enabling orchestration similar to Langchain. ```cangjie let group = FooAgent() |> ToolAgent(fn: { q: String => ...; }) |> BarAgent() ``` -------------------------------- ### SemanticMap Usage Example Source: https://github.com/cangjiepl/cangjiemagic/blob/dev/docs/tutorial.md Demonstrates the basic usage of SemanticMap, including initialization with an InMemoryVectorDatabase, adding key-value pairs, and performing a semantic search. The output of the search is printed to the console. ```cangjie import magic.rag.vdb.* main() { let smap = SemanticMap(vectorDB: InMemoryVectorDatabase()) smap.put("前往上海", "Plan A") smap.put("吃饭", "Plan B") smap.put("前往北京", "Plan C") smap.put("睡觉", "Plan D") let c = smap.search("前往上海", number: 2) println(c) } ``` -------------------------------- ### AI Function Execution Example Source: https://context7.com/cangjiepl/cangjiemagic/llms.txt Demonstrates calling AI functions defined with the `@ai` macro, including translation, keyword extraction, and sentiment analysis with structured output. Ensure necessary imports are present. ```cangjie main() { // 翻译 let en = translate("今天天气真好!", "English") println(en) // 输出: The weather is really nice today! // 提取关键词 let keywords = extractKeywords("https://cangjie-lang.cn/") println(keywords) // 输出: ["仓颉", "编程语言", "鸿蒙", ...] // 情感分析(结构化输出) let result = analyzeSentiment("这个产品非常好用,强烈推荐!") println("情感: ${result.sentiment}, 置信度: ${result.confidence}") // 输出: 情感: positive, 置信度: 0.95 } ``` -------------------------------- ### Build Vector Example Source: https://github.com/cangjiepl/cangjiemagic/blob/dev/docs/tutorial.md Demonstrates how to create an embedding vector using the VectorBuilder. It involves obtaining an embedding model instance via ModelManager and then using the builder to create a vector from a string. ```cangjie let model = ModelManager.createEmbeddingModel("openai:text-embedding-ada-002") let vecBuilder = VectorBuilder(model: model) let vector= vecBuilder.createEmbeddingVector("第一条向量") ``` -------------------------------- ### Agent with Rag Configuration for External Knowledge Source: https://github.com/cangjiepl/cangjiemagic/blob/dev/docs/tutorial.md Configures an agent to use external knowledge sources via the 'rag' property. This example specifies a dynamic mode for a markdown file located at 'path/to/some.md'. ```cangjie @agent[ rag: { source: "path/to/some.md", mode: "dynamic" } ] class Foo { } ``` -------------------------------- ### Linear Agent Collaboration Source: https://github.com/cangjiepl/cangjiemagic/blob/dev/docs/tutorial.md Demonstrates how to create a 'LinearGroup' of agents using the pipe operator '|>'. This setup allows agents to process information sequentially, passing results from one to the next. ```cangjie let linearGroup: LinearGroup = ag1 |> ag2 |> ag3 ``` -------------------------------- ### Custom Chat Model Implementation Source: https://github.com/cangjiepl/cangjiemagic/blob/dev/docs/tutorial.md Example of implementing a custom chat model by extending ChatModel and assigning it to an agent. The model can be registered by name for direct configuration in @agent properties. ```cangjie @agent class Foo { } class NewModel <: ChatModel { public func create(req: ChatRequest): ChatResponse { ... } public func asyncCreate(req: ChatRequest): AsyncChatResponse { ... } } let foo = Foo() foo.model = NewModel() ``` -------------------------------- ### Human-in-the-Loop (HITL) Execution Example Source: https://context7.com/cangjiepl/cangjiemagic/llms.txt Demonstrates the combined use of global, agent-level, and request-level event handlers. A `SecureAgent` is set up with an agent-level handler to block `deleteFile`. Global handlers log tool calls and agent completion. A specific request uses `@interact` to authorize the `deleteFile` operation, overriding the agent-level block. ```cangjie main() { setupGlobal() let agent = SecureAgent() // 请求级别:临时授权特定操作 @interact[ agent: agent, request: AgentRequest("删除 /tmp/cache.log 文件(已获授权)") ]( case evt: ToolCallStartEvent => if (evt.toolRequest.name == "deleteFile") { println("[请求] 此请求已获授权,允许删除") return EventResponse.Continue // 覆盖 Agent 级别拦截 } return EventResponse.Continue ) // 普通请求(deleteFile 会被 Agent 级别拦截) let result = agent.chat("请帮我删除 /tmp/old.log") println(result) } ``` -------------------------------- ### AI Function with Tools: Extracting Keywords Source: https://context7.com/cangjiepl/cangjiemagic/llms.txt Integrate external tools into AI functions using the `@ai` macro. The `tools` parameter accepts a list of functions that the LLM can call. This example extracts keywords from a webpage using a `fetchPage` tool. ```cangjie @tool[description: "获取网页 HTML 内容"] func fetchPage(url: String): String { // 实际 HTTP 请求 return "..." } @ai[ prompt: "提取最重要的关键词,不超过 5 个", model: "deepseek:deepseek-chat", tools: [fetchPage] ] foreign func extractKeywords(url: String): Array ``` -------------------------------- ### Custom Agent Executor Implementation Source: https://github.com/cangjiepl/cangjiemagic/blob/dev/docs/tutorial.md Example of implementing a custom agent executor by extending AgentExecutor and assigning it to an agent. The executor can be registered by name for direct configuration in @agent properties. ```cangjie @agent class Foo { } class NewExecutor <: AgentExecutor { func run(agent: Agent, request: AgentRequest): AgentResponse { ... } func asyncRun(agent: Agent, request: AgentRequest): AsyncAgentResponse { ... } } let foo = Foo() foo.executor = NewExecutor() ``` -------------------------------- ### Embedding Model Implementations Source: https://github.com/cangjiepl/cangjiemagic/blob/dev/docs/tutorial.md Lists example implementations for the EmbeddingModel interface, specifically OpenAI and Ollama. These models are used by VectorBuilder to create embeddings. ```cangjie class OpenAIEmbeddingModel <: EmbeddingModel { ... } class OllamaEmbeddingModel <: EmbeddingModel { ... } ``` -------------------------------- ### VectorDatabase Interface Source: https://github.com/cangjiepl/cangjiemagic/blob/dev/docs/tutorial.md Defines the interface for vector databases, including methods for adding vectors, searching for similar data, and saving/loading the database. The index must start from 0. ```cangjie public interface VectorDatabase { /** * Add the vector to the database * ATTENTION: index must start from 0 */ func addVector(vector: Vector): Unit /** * Query the database and find indexes of similar data */ func search(queryVec: Vector, number!: Int64): Array /** * Save to the file */ func save(filePath: String): Unit /** * Load from the file */ static func load(filePath: String): Self } ``` -------------------------------- ### Building Agents with BaseAgent API Source: https://context7.com/cangjiepl/cangjiemagic/llms.txt Shows how to dynamically create and configure agents using the BaseAgent class via its API, including setting properties like name, description, system prompt, model, and temperature, as well as adding tools. ```cangjie import magic.dsl.* import magic.prelude.* import magic.agent.base.* main() { // 使用 API 构建 Agent let agent = BaseAgent( name: "代码助手", description: "负责代码审查和优化建议", systemPrompt: "你是一个资深代码审查专家,擅长发现代码中的性能问题和安全漏洞。", model: ModelManager.createChatModel("deepseek:deepseek-chat"), temperature: 0.3 ) // 动态修改属性 agent.systemPrompt = "你是一个 Python 专家,专注于数据科学领域的代码优化。" agent.model = ModelManager.createChatModel("openai:gpt-4o") // 动态添加工具 @tool[description: "运行 Python 代码片段并返回结果"] func runPython(code: String): String { return "执行结果..." } agent.toolManager.addTool(runPython) let review = agent.chat(""" 请审查以下代码: def find_max(lst): max_val = 0 for i in lst: if i > max_val: max_val = i return max_val """) println(review) // 输出: 代码存在问题:初始值 0 会导致全负数列表返回错误结果,建议改用 lst[0] 或 float('-inf') } ``` -------------------------------- ### Using the APE Prompt Pattern Source: https://github.com/cangjiepl/cangjiemagic/blob/dev/docs/tutorial.md Demonstrates how to use the predefined APE prompt pattern within an agent. Ensure the prompt elements match the pattern's requirements. ```cangjie @agent class Foo { @prompt[pattern: APE] ( action: "帮助用户制定旅行路线", purpose: "让用户在计划的时间内尽可能多地参观景点并得到充分休息", expectation: "生成一条合理的旅行路线,包括时间、景点、通勤等信息" ) } ``` -------------------------------- ### Using Input Templates with Agents Source: https://github.com/cangjiepl/cangjiemagic/blob/dev/docs/tutorial.md Shows how to define input templates for agents using the @user macro. Placeholders within the template are filled when calling the chat method with variables. ```cangjie @agent class Foo { @prompt( "System: ..." ) @user( "矩形的长为:{length} cm,宽为 {width} cm" "计算矩形的面积" ) } let agent = Foo() let area = agent.chat( ("length", 3), ("width", 4), ) ``` -------------------------------- ### 编写 Agent 系统提示词(使用外部文件) Source: https://github.com/cangjiepl/cangjiemagic/blob/dev/docs/tutorial.md 使用 `@prompt` 宏的 `include` 属性,可以将外部文件的内容作为 Agent 的系统提示词。当配置 `include` 时,宏内编写的字面量将失效。 ```cangjie @agent class Foo { @prompt[include: "./a.md"]() } ``` -------------------------------- ### Define Toolset Type and Configure Source: https://github.com/cangjiepl/cangjiemagic/blob/dev/docs/tutorial.md Define a Toolset with @toolset and its member methods as tools. Instantiate the Toolset and list it in the agent's 'tools' property. ```cangjie @toolset class FooToolset { @tool[description: "..."] func foo(arg: String): String { ... } @tool[description: "..."] func bar(): String { ... } } @agent[ tools: [FooToolset()] ] class A { ... } ``` -------------------------------- ### Model Configuration and Custom Models Source: https://context7.com/cangjiepl/cangjiemagic/llms.txt Explains how to configure API keys, service URLs for built-in models, and how to register and use custom chat models by implementing the ChatModel interface. ```cangjie import magic.dsl.* import magic.prelude.* import magic.config.Config import magic.core.model.* // 自定义模型实现 class MyCustomModel <: ChatModel { public func create(req: ChatRequest): ChatResponse { // 实现自定义模型调用逻辑 let messages = req.messages return ChatResponse(content: "自定义模型回复: ${messages.last().content}") } public func asyncCreate(req: ChatRequest): AsyncChatResponse { // 异步实现 return AsyncChatResponse(...) } } main() { // 配置多种模型的 API Key Config.env["DEEPSEEK_API_KEY"] = "sk-xxx" Config.env["OPENAI_API_KEY"] = "sk-yyy" Config.env["DASHSCOPE_API_KEY"] = "sk-zzz" // 自定义服务地址(如私有化部署) Config.env["OPENAI_BASE_URL"] = "https://my-private-openai.com/v1" // 注册自定义模型 ModelManager.register("myModel", { => MyCustomModel() }) // 通过属性使用注册的自定义模型 @agent[model: "myModel"] class MyAgent { @prompt("你使用自定义模型提供服务。") } // 通过 API 直接设置模型 @agent class Foo {} let foo = Foo() foo.model = MyCustomModel() println(foo.chat("你好")) // 使用 ModelManager 创建内置模型 let chatModel = ModelManager.createChatModel("ollama:llama3") let embedModel = ModelManager.createEmbeddingModel("openai:text-embedding-3-small") } ``` -------------------------------- ### Configure MCP Servers using JSON Syntax Source: https://github.com/cangjiepl/cangjiemagic/blob/dev/docs/tutorial.md Configure MCP servers (stdio, sse) within the agent's 'tools' property using a JSON-like object syntax, including command, arguments, environment variables, and URLs. ```cangjie @agent[ tools: [ { command: "node", args: [ "index.js", "args" ] }, { command: "python", args: [ "main.py", "args" ], env: { SOME_API_KEY: "xxx" } }, { url: "http://abc.mcp.server.com" } ] ] class Foo { ... } ``` -------------------------------- ### Request-Level Event Interception with @interact Source: https://context7.com/cangjiepl/cangjiemagic/llms.txt Use the `@interact` decorator for request-level event interception, allowing temporary authorization or modification of behavior for specific requests. This example overrides the agent-level handler to permit a `deleteFile` operation that has been explicitly authorized. ```cangjie // 请求级别:临时授权特定操作 @interact[ agent: agent, request: AgentRequest("删除 /tmp/cache.log 文件(已获授权)") ]( case evt: ToolCallStartEvent => if (evt.toolRequest.name == "deleteFile") { println("[请求] 此请求已获授权,允许删除") return EventResponse.Continue // 覆盖 Agent 级别拦截 } return EventResponse.Continue ) ``` -------------------------------- ### Configure DeepSeek API Key Source: https://github.com/cangjiepl/cangjiemagic/blob/dev/src/examples/markdown_qa/README.md Set your DeepSeek API key in the main configuration file. Replace the placeholder with your actual key. ```cangjie Config.env["DEEPSEEK_API_KEY"] = "sk-xxxxxxxxxx"; ``` -------------------------------- ### Initialize HumanAgent Source: https://github.com/cangjiepl/cangjiemagic/blob/dev/docs/tutorial.md Instantiate a HumanAgent, optionally providing a custom function to handle user questions and input. The default behavior prints the question and reads user input. ```cangjie class HumanAgent { public init(qaFunc!: Option<(String) -> String> = None) } ``` ```cangjie let humanAgent = HumanAgent(qaFunc: { q: String => println(q); return "answer" }) let result = humanAgent.chat("question") ``` -------------------------------- ### Simple AI Function: Translation with @ai Macro Source: https://context7.com/cangjiepl/cangjiemagic/llms.txt Use the `@ai` macro to define functions whose logic is executed by an LLM. Ensure function parameters and return types implement the `Jsonable` interface. This example shows a basic translation function. ```cangjie import magic.dsl.* import magic.prelude.* // 简单 AI 函数:翻译 @ai[model: "deepseek:deepseek-chat"] foreign func translate(text: String, targetLang: String): String ``` -------------------------------- ### 编写 Agent 系统提示词(访问成员变量) Source: https://github.com/cangjiepl/cangjiemagic/blob/dev/docs/tutorial.md 在 `@prompt` 宏中可以访问 Agent 的成员变量,例如 `name` 和 `version`。这允许提示词动态地包含 Agent 的特定信息。 ```cangjie @agent class Calculator { @prompt( """ 你是一个计算器,能够进行计算。 你的名字是 ${name}-${version}。 """ "例如,你可以加法运算,1 + 2 = 3 ..." ) private let name: String private let version: Int64 ... } let calculator = Calculator(name: "aha", version: 1) ``` -------------------------------- ### Agent-Level Event Interception with @handler Source: https://context7.com/cangjiepl/cangjiemagic/llms.txt Implement agent-level event handlers using the `@handler` decorator to intercept and manage events throughout the agent's lifecycle. This example demonstrates blocking a dangerous `deleteFile` tool call and handling LLM failures. ```cangjie import magic.dsl.* import magic.interaction.* import magic.core.interaction.* @agent[model: "deepseek:deepseek-chat", executor: "react"] class SecureAgent { // Agent 级别拦截器:对所有请求生效 @handler( case evt: ToolCallStartEvent => if (evt.toolRequest.name == "deleteFile") { println("[安全] 拦截危险操作:deleteFile,需要人工审批") return EventResponse.Terminate(ToolResponse( result: "操作被安全策略拦截,请联系管理员", isError: true )) } return EventResponse.Continue case evt: ChatModelFailureEvent => println("[错误] LLM 调用失败: ${evt.error}") return EventResponse.Continue ) @tool[description: "读取文件内容"] func readFile(path: String): String { return "文件内容" } @tool[description: "删除文件(危险操作)"] func deleteFile(path: String): String { return "已删除" } } ``` -------------------------------- ### Configure Agent Executor - Naive Source: https://github.com/cangjiepl/cangjiemagic/blob/dev/docs/tutorial.md Set the agent's executor to 'naive' for direct question-answering behavior. ```cangjie @agent[executor: "naive"] class Foo{ } ``` -------------------------------- ### AI Function Returning Structured Data with @jsonable Source: https://context7.com/cangjiepl/cangjiemagic/llms.txt Define custom classes annotated with `@jsonable` to receive structured data from AI functions. The `@ai` macro can then be configured to return instances of these classes. This example analyzes sentiment and returns a `SentimentResult` object. ```cangjie // 返回结构化数据的 AI 函数 @jsonable class SentimentResult { @field["情感倾向:positive / negative / neutral"] let sentiment: String @field["置信度 0.0 ~ 1.0"] let confidence: Float64 let summary: String } @ai[model: "deepseek:deepseek-chat", temperature: 0.3] foreign func analyzeSentiment(text: String): SentimentResult ``` -------------------------------- ### Define and Configure Global Tool Source: https://github.com/cangjiepl/cangjiemagic/blob/dev/docs/tutorial.md Use the @tool macro to convert a global function into a tool. Specify the tool in the agent's 'tools' property to make it available. ```cangjie @tool[description: "...", parameters: { arg: "..."}] func foo(arg: String): String { ... } @agent[ tools: [foo] ] class A { ... } ``` -------------------------------- ### 编写 Agent 系统提示词(字符串拼接) Source: https://github.com/cangjiepl/cangjiemagic/blob/dev/docs/tutorial.md 使用 `@prompt` 宏在 Agent 定义中编写系统提示词。宏作用域内的字符串字面量会被拼接成完整的提示词。支持插值字符串和访问仓颉语言的函数及成员变量。 ```cangjie @agent class Foo { @prompt( "# This is a Foo agent" "## Description" "balabala ${bar()}" ) } ``` -------------------------------- ### Build a Linear Collaboration Subgroup Source: https://github.com/cangjiepl/cangjiemagic/blob/dev/docs/tutorial.md Illustrates constructing a linear collaboration group where one unit is a master-slave subgroup. This syntax is for building complex agent interactions. ```cangjie ag1 |> (ag2 <= [ag3]) |> ag4 ``` -------------------------------- ### Semantic Vector Search with SemanticMap Source: https://context7.com/cangjiepl/cangjiemagic/llms.txt Demonstrates building a semantic map for key-value storage with vector embeddings, inserting data, performing similarity searches, and integrating with an agent. Includes saving and loading the vector database. ```cangjie import magic.dsl.* import magic.prelude.* import magic.rag.vdb.* main() { // 构建语义 Map(key: 语义查询键, value: 存储内容) let smap = SemanticMap( vectorDB: InMemoryVectorDatabase(), indexMap: SimpleIndexMap(), embeddingModel: ModelManager.createEmbeddingModel("openai:text-embedding-ada-002") ) // 插入数据 smap.put("北京旅游攻略", "北京有故宫、长城、颐和园等著名景点,推荐春秋季节游览。") smap.put("上海旅游攻略", "上海有外滩、迪士尼、豫园等,适合全年游览。") smap.put("成都美食推荐", "成都以火锅、串串、担担面等川菜闻名,必吃宽窄巷子小吃。") smap.put("杭州景点介绍", "杭州西湖风景秀丽,龙井茶叶和丝绸是著名特产。") // 语义相似度搜索(返回最相关的 2 条结果) let results = smap.search("我想去首都看古建筑", number: 2, minDistance: 0.2) for (r in results) { println(r) } // 输出: 北京有故宫、长城... // 将向量库作为 Retriever 绑定到 Agent @agent[model: "deepseek:deepseek-chat"] class TravelAgent { @prompt("你是旅游助手,根据知识库回答用户的旅行咨询。") } let agent = TravelAgent() agent.retriever = smap.asRetriever() println(agent.chat("我对古代文化很感兴趣,去哪里旅游比较好?")) // 输出: 建议您去北京,故宫和长城是体验古代文化的最佳选择... // 持久化与加载 smap.save("./travel_knowledge") // 下次启动时加载 // let loaded = SemanticMap.load("./travel_knowledge") } ``` -------------------------------- ### 定义 Agent 类型 Source: https://github.com/cangjiepl/cangjiemagic/blob/dev/docs/tutorial.md 使用 `@agent` 宏修饰 class 来定义一个 Agent 类型。该宏支持 description, model, tools, rag, memory, executor, temperature, enableToolFilter, 和 dump 等属性。 ```cangjie @agent class Foo { } ``` -------------------------------- ### Configure Agent Executor - React Source: https://github.com/cangjiepl/cangjiemagic/blob/dev/docs/tutorial.md Set the agent's executor to 'react' for step-by-step problem solving using tools. Optionally specify the maximum number of iterations, e.g., 'react:5'. ```cangjie @agent[executor: "react"] class Bar{ } ``` -------------------------------- ### Configure Agent Tools with MCP Servers and Functions Source: https://github.com/cangjiepl/cangjiemagic/blob/dev/docs/tutorial.md Configure an agent to use various MCP servers (stdio, sse, http) and custom tool functions or toolsets via the 'tools' property. ```cangjie @agent[ tools: [ stdioMCP("node index.js args" ), stdioMCP("python main.py args", SOME_API_KEY: "xxx"), httpMCP("http://abc.mcp.server.com"), toolA, toolB, SomeToolset() ] ] class Foo { ... } ``` -------------------------------- ### Asynchronous Agent Execution with Streaming Output Source: https://context7.com/cangjiepl/cangjiemagic/llms.txt Leverage `asyncChat()` for asynchronous agent operations, returning an `AsyncAgentResponse`. Use `ConsolePrinter` for real-time streaming of execution steps or implement a custom `EventStreamVisitor` for detailed monitoring and handling of agent events. ```cangjie import magic.dsl.* import magic.prelude.* import magic.interaction.ConsolePrinter import magic.parser.* @agent[model: "deepseek:deepseek-chat", executor: "react"] class ResearchBot { @prompt("你是一个研究助手,能够系统地分析复杂问题并给出详细解答。") @tool[description: "搜索学术资料"] func searchPapers(query: String): String { return "论文摘要..." } } main() { let agent = ResearchBot() // 方式一:使用 ConsolePrinter 打印执行过程 let asyncResp = agent.asyncChat( AgentRequest("分析大语言模型在代码生成领域的最新进展", verbose: true) ) // verbose: true 开启详细日志,ConsolePrinter 实时打印执行步骤 ConsolePrinter.print(asyncResp, verbose: true) // 控制台输出示例: // [Think] 我需要搜索 LLM 代码生成相关论文... // [Action] 调用 searchPapers("LLM code generation 2024") // [Result] 找到 15 篇相关论文... // [Answer] 根据最新研究... // 方式二:自定义事件处理器 class MyPrinter <: EventStreamVisitor { public init(events: EventStream) { super(events) } override public func on(event: NotifyEvent): Unit { println("[通知] ${event.content.trimAscii()}") } override public func on(event: ToolCallStartEvent): Unit { println("[工具] 开始调用: ${event.toolRequest.name}") } override public func on(event: AgentEndEvent): Unit { println("[完成] Agent 执行结束") } } let asyncResp2 = agent.asyncChat(AgentRequest("LLM 代码补全技术综述", verbose: true)) let printer = MyPrinter(asyncResp2.execution.events) printer.start() } ``` -------------------------------- ### Agent Interaction Interfaces: chat() and chatGet() Source: https://context7.com/cangjiepl/cangjiemagic/llms.txt Use chat() for basic string interactions with an agent, supporting string questions, template variables, and AgentRequest. Use chatGet() to retrieve structured data directly. ```cangjie import magic.dsl.* import magic.prelude.* // 定义可序列化的数据结构 @jsonable class CompanyInfo { @field["公司成立年份"] let foundedYear: Int64 @field["公司总部所在城市"] let headquarters: String let employeeCount: Int64 } // 带输入模板的 Agent @agent class ResearchAgent { @prompt("你是一个企业信息查询助手,提供准确的企业基本信息。") @user( "请查询 {company} 公司的基本信息" "包括成立年份、总部城市和员工数量" ) } main() { let agent = ResearchAgent() // 方式一:直接字符串提问 let answer = agent.chat("介绍一下华为公司") println(answer) // 方式二:使用输入模板(占位符替换) let formatted = agent.chat(("company", "阿里巴巴")) println(formatted) // 方式三:返回结构化数据 let info = agent.chatGet("华为的基本信息") match (info) { case Some(v) => println("成立年份: ${v.foundedYear}, 总部: ${v.headquarters}") case None => println("无法获取结构化数据") } // 输出示例:成立年份: 1987, 总部: 深圳 } ``` -------------------------------- ### Defining a Custom Prompt Pattern Source: https://github.com/cangjiepl/cangjiemagic/blob/dev/docs/tutorial.md Shows how to define a new prompt pattern named 'APE' using the @promptPattern macro. Elements within the pattern are defined using @element and must be of String type. ```cangjie @promptPattern class APE { @element[description: "定义任务"] let action: String @element[description: "定义任务原因"] let purpose: String @element[description: "清晰地定义期望结果"] let expectation: String public func toString(): String { return "...${action}...${purpose}...${expectation}..." } } ``` -------------------------------- ### Integrate MCP Servers with @agent Source: https://context7.com/cangjiepl/cangjiemagic/llms.txt Agents can connect to external tool servers using the `tools` property in the `@agent` macro, supporting `stdio` and `http/sse` protocols. MCP tools can also be added dynamically via API. ```cangjie import magic.dsl.* import magic.prelude.* // 方式一:在 @agent 属性中静态配置 MCP @agent[ model: "openai:gpt-4o", executor: "react", tools: [ // stdio 协议:启动本地 MCP 服务进程 stdioMCP("node ./mcp-server/index.js"), stdioMCP("python tools/search_server.py", SEARCH_API_KEY: "sk-xxxx"), // http/sse 协议:连接远程 MCP 服务 httpMCP("https://api.example.com/mcp"), // JSON 语法配置 { command: "node", args: ["weather-mcp/index.js"], env: { WEATHER_KEY: "xxx" } } ] ] class PowerfulAgent { @prompt("你是一个功能强大的助手,可以搜索网页、查询天气和处理文件。" ) } // 方式二:通过 API 动态添加 MCP 工具 func buildDynamicAgent() { let client = MCPClient("node", ["./mcp-tools/index.js"]) let agent = PowerfulAgent() // 动态注入 MCP 工具 agent.toolManager.addTools(client.getTools()) let result = agent.chat("搜索最新的 Cangjie 语言新闻") println(result) } main() { buildDynamicAgent() } ``` -------------------------------- ### Define an AI Agent with @agent Macro Source: https://context7.com/cangjiepl/cangjiemagic/llms.txt Use the @agent macro on a class to transform it into an AI Agent. Configure model, executor, memory, and temperature. The agent automatically gains a chat() method. ```cangjie import magic.dsl.* import magic.prelude.* import magic.config.Config // 定义一个具备 react 规划、记忆、工具的 Agent @agent[ model: "deepseek:deepseek-chat", executor: "react:5", // react 模式,最多 5 轮迭代 memory: true, temperature: 0.7 ] class WeatherAssistant { @prompt( "你是一个天气助手,能够查询天气并给出出行建议。" "每次回答时请附上当前日期和温度信息。" ) @tool[ description: "查询指定城市的当前天气", parameters: { city: "城市名称(中文或英文)" } ] func getWeather(city: String): String { // 实际项目中调用天气 API return "晴天,25°C,微风" } } main() { Config.env["DEEPSEEK_API_KEY"] = "your-api-key" let agent = WeatherAssistant() let result = agent.chat("北京今天天气怎么样,适合出门吗?") println(result) // 输出示例:今天北京晴天,25°C,微风,非常适合出门游玩。 } ``` -------------------------------- ### Define Custom Prompt Patterns with @promptPattern Source: https://context7.com/cangjiepl/cangjiemagic/llms.txt Use the @promptPattern macro on a class to define new structured prompt patterns. Use @element to annotate members as prompt elements and implement toString() to construct the final prompt string. ```cangjie // 定义 STAR 提示词模式(情境-任务-行动-结果) @promptPattern class STAR { @element[description: "描述背景情境"] let situation: String @element[description: "定义具体任务"] let task: String @element[description: "描述需要执行的行动"] let action: String @element[description: "说明期望结果"] let result: String public func toString(): String { return """ 【情境】${situation} 【任务】${task} 【行动】${action} 【期望结果】${result} """ } } // 使用自定义 STAR 模式 @agent class InterviewCoach { @prompt[pattern: STAR]( situation: "用户正在准备技术面试", task: "帮助用户用 STAR 法则组织面试回答", action: "引导用户描述具体情境、任务、行动和结果", result: "生成结构清晰、逻辑连贯的面试回答示例" ) } main() { let coach = InterviewCoach() println(coach.chat("如何回答'描述一个你解决复杂 bug 的经历'")) } ``` -------------------------------- ### Implement a Guessing Game with FreeGroup Source: https://github.com/cangjiepl/cangjiemagic/blob/dev/docs/tutorial.md Demonstrates a two-agent number guessing game using FreeGroup with the RoundRobin mode. Ensure agents are defined with appropriate prompts. ```cangjie @agent class AgentWithNumber { @prompt( "You are playing a game of guess-my-number. You have the " "number 33 in your mind, and I will try to guess it. " "If I guess too high, say 'too high', if I guess too low, say 'too low'." ) } @agent class AgentGuessNumber { @prompt( "I have a number in my mind, and you will try to guess it. " "If I say 'too high', you should guess a lower number. If I say 'too low', " "you should guess a higher number. " ) } func game() { let group = AgentWithNumber() | AgentGuessNumber() group.discuss(topic: "Number guessing game", initiator: "AgentWithNumber", speech: "I have a number between 1 and 70. Guess it!", mode: FreeGroupMode.RoundRobin) } ``` -------------------------------- ### Adding Vector Database as Retriever to Agent Source: https://github.com/cangjiepl/cangjiemagic/blob/dev/docs/tutorial.md Shows how to integrate a SemanticMap's retriever functionality into an agent. Currently, the vector database can only be used in a static mode. ```cangjie let agent = FooAgent() agent.retriever = smap.asRetriever() ``` -------------------------------- ### Basic Agent Interaction Source: https://github.com/cangjiepl/cangjiemagic/blob/dev/docs/tutorial.md Illustrates the default chat interaction method for an agent. Agents defined with @agent have a chat function for string-based input and output. ```cangjie @agent class Foo { ... } let agent = Foo() let result = agent.chat("What's the weather today?") println(result) ``` -------------------------------- ### Define System Prompts with @prompt Macro Source: https://context7.com/cangjiepl/cangjiemagic/llms.txt Use the @prompt macro within an Agent class to define system prompts. Supports string concatenation, interpolation, external file loading, and structured prompt patterns. ```cangjie // 方式一:内联字符串拼接(支持插值) @agent class Calculator { private let version: String = "v2.0" @prompt( "你是计算器助手 ${version}。" "你能执行加减乘除以及复杂的数学运算。" "每次计算时,展示完整的推理步骤。" ) } // 方式二:从外部 Markdown 文件加载提示词 @agent class DocAgent { @prompt[include: "./prompts/doc_agent_system.md"]() } // 方式三:使用结构化 APE 提示词模式 @agent class TravelPlanner { @prompt[pattern: APE]( action: "为用户规划旅行路线", purpose: "让用户在计划时间内尽量游览更多景点,同时获得充分休息", expectation: "生成合理的旅行路线,包含时间、景点、交通信息等" ) } main() { let calc = Calculator() println(calc.chat("计算 (123 + 456) × 789 ÷ 3")) // 输出示例:步骤1: 123+456=579;步骤2: 579×789=456,831;步骤3: 456,831÷3=152,277 } ``` -------------------------------- ### Define Global and Toolset Functions with @tool and @toolset Source: https://context7.com/cangjiepl/cangjiemagic/llms.txt Use the `@tool` macro to mark functions as callable by an Agent, supporting global functions, member methods, and Toolset methods. The `@toolset` macro organizes tool methods into a class for better management. ```cangjie import magic.dsl.* import magic.prelude.* // 定义全局工具函数 @tool[ description: "执行 Shell 命令并返回输出结果", parameters: { cmd: "要执行的命令字符串" }, terminal: false, // 不终止 Agent 执行 filterable: true // 允许 Agent 按需过滤此工具 ] func runShell(cmd: String): String { // 实际执行命令 return "命令执行结果..." } // 定义工具集(批量管理工具) @toolset class FileToolset { @tool[description: "读取文件内容", parameters: { path: "文件路径" }] func readFile(path: String): String { return "文件内容..." } @tool[description: "写入文件内容", parameters: { path: "文件路径", content: "写入内容" }] func writeFile(path: String, content: String): String { return "写入成功" } } // Agent 使用全局工具 + 工具集 + 内部工具 @agent[ model: "deepseek:deepseek-chat", executor: "react", tools: [runShell, FileToolset()] // 引用全局工具和工具集实例 ] class DevAssistant { @prompt("你是一个开发助手,能够执行命令、读写文件。" ) // 内部工具(无需在 tools 属性中声明) @tool[description: "格式化代码", parameters: { code: "待格式化的代码" }] func formatCode(code: String): String { return "// 已格式化\n${code}" } } main() { let agent = DevAssistant() println(agent.chat("读取 ./README.md 文件并统计行数")) } ``` -------------------------------- ### Agent Interaction Returning Data Types Source: https://github.com/cangjiepl/cangjiemagic/blob/dev/docs/tutorial.md Demonstrates using the chatGet method to have an agent return a specific data type instead of just a string. The returned type must implement the Jsonable interface. ```cangjie @jsonable class MyDate { @field["Year of the foundation"] let year: Int64 let month: Int64 } @agent class Foo { } let agent = Foo() let date = agent.chatGet("华为创建时间") println(date.year) println(date.month) ```