diff --git a/docs/docs/memory/long-term-memory.md b/docs/docs/memory/long-term-memory.md index 19d04b22..d9177e18 100644 --- a/docs/docs/memory/long-term-memory.md +++ b/docs/docs/memory/long-term-memory.md @@ -28,27 +28,87 @@ title: 长期记忆 ## 初始化方法 在使用长期记忆之前,需要实例化 LongTermMemory 对象并指定后端类型。以下代码展示了如何初始化基于 VikingDB 的长期记忆模块,并将其绑定到 Agent: - -```python -from veadk import Agent, Runner -from veadk.memory import LongTermMemory - -# 初始化长期记忆 -# backend="viking" 指定使用 VikingDB -# app_name 和 user_id 用于数据隔离 -long_term_memory = LongTermMemory( - backend="viking", app_name="local_memory_demo", user_id="demo_user" -) - -# 将长期记忆绑定到 Agent -root_agent = Agent( - name="minimal_agent", - instruction="Acknowledge user input and maintain simple conversation.", - long_term_memory=long_term_memory, # 长期记忆实例 -) - -runner = Runner(agent=root_agent) -``` +=== "Python" + + ```python + from veadk import Agent, Runner + from veadk.memory import LongTermMemory + + # 初始化长期记忆 + # backend="viking" 指定使用 VikingDB + # app_name 和 user_id 用于数据隔离 + long_term_memory = LongTermMemory( + backend="viking", app_name="local_memory_demo", user_id="demo_user" + ) + + # 将长期记忆绑定到 Agent + root_agent = Agent( + name="minimal_agent", + instruction="Acknowledge user input and maintain simple conversation.", + long_term_memory=long_term_memory, # 长期记忆实例 + ) + + runner = Runner(agent=root_agent) + ``` + +=== "Golang" + + ```go + package main + + import ( + "log" + + veagent "github.com/volcengine/veadk-go/agent/llmagent" + "github.com/volcengine/veadk-go/common" + vem "github.com/volcengine/veadk-go/memory" + "github.com/volcengine/veadk-go/tool/builtin_tools" + "github.com/volcengine/veadk-go/utils" + "google.golang.org/adk/runner" + "google.golang.org/adk/session" + "google.golang.org/adk/tool" + ) + + func main() { + appName := "ve_agent" + memorySearchTool, err := builtin_tools.LoadLongMemoryTool() + if err != nil { + log.Fatal(err) + return + } + + cfg := &veagent.Config{ + ModelName: common.DEFAULT_MODEL_AGENT_NAME, + ModelAPIBase: common.DEFAULT_MODEL_AGENT_API_BASE, + ModelAPIKey: utils.GetEnvWithDefault(common.MODEL_AGENT_API_KEY), + } + cfg.Name = "MemoryRecallAgent" + cfg.Instruction = "Answer the user's question. Use the 'search_past_conversations' tools if the answer might be in past conversations." + + cfg.Tools = []tool.Tool{memorySearchTool} + + memorySearchAgent, err := veagent.New(cfg) + if err != nil { + log.Printf("NewLLMAgent failed: %v", err) + return + } + + sessionService := session.InMemoryService() + memoryService, err := vem.NewLongTermMemoryService(vem.BackendLongTermViking, nil) + if err != nil { + log.Printf("NewLongTermMemoryService failed: %v", err) + return + } + + runner, err := runner.New(runner.Config{ + AppName: appName, + Agent: memorySearchAgent, + SessionService: sessionService, + MemoryService: memoryService, + }) + } + + ``` ## 记忆管理 @@ -56,31 +116,67 @@ runner = Runner(agent=root_agent) 在会话(Session)结束或达到特定节点时,需要显式调用 add_session_to_memory 将会话数据持久化。对于 Viking 后端,这一步会触发数据的向量化处理。 -```python -# 假设 runner1 已经完成了一次对话 -completed_session = await runner.session_service.get_session( - app_name=APP_NAME, user_id=USER_ID, session_id=session_id -) - -# 将完整会话归档到长期记忆 -root_agent.long_term_memory.add_session_to_memory(completed_session) -``` +=== "Python" + + ```python + # 假设 runner1 已经完成了一次对话 + completed_session = await runner.session_service.get_session( + app_name=APP_NAME, user_id=USER_ID, session_id=session_id + ) + + # 将完整会话归档到长期记忆 + root_agent.long_term_memory.add_session_to_memory(completed_session) + ``` +=== "Golang" + + ```go + appName := "ve_agent" + userID := "user1111" + sessionService := session.InMemoryService() + s, err := sessionService.Create(ctx, &session.CreateRequest{ + AppName: appName, + UserID: userID, + SessionID: sessionID, + }) + + resp, err := sessionService.Get(ctx, &session.GetRequest{AppName: s.Session.AppName(), UserID: s.Session.UserID(), SessionID: s.Session.ID()}) + if err != nil { + log.Fatalf("Failed to get completed session: %v", err) + } + if err := memoryService.AddSession(ctx, resp.Session); err != nil { + log.Fatalf("Failed to add session to memory: %v", err) + } + ``` ### 检索长期记忆 除了 Agent 在运行时自动检索外,开发者也可以调用 search_memory 接口直接进行语义搜索,用于调试或构建自定义的 RAG(检索增强生成)应用。 -```python -query = "favorite project" -res = await root_agent.long_term_memory.search_memory( - app_name=APP_NAME, - user_id=USER_ID, - query=query -) +=== "Python" + + ```python + query = "favorite project" + res = await root_agent.long_term_memory.search_memory( + app_name=APP_NAME, + user_id=USER_ID, + query=query + ) + + # 打印检索结果 + print(res) + ``` + +=== "Golang" + + ```go + query := "favorite project" + memoryService.Search(ctx, &memory.SearchRequest{ + Query: query, + UserID: userID, + AppName: appName, + }) + ``` -# 打印检索结果 -print(res) -``` ## 使用长期记忆进行会话管理 @@ -100,37 +196,209 @@ print(res) 以下示例演示了一个完整的流程:Runner1 告诉 Agent 一个信息("My favorite project is Project Alpha"),将会话存入记忆,然后创建一个全新的 Runner2,验证其能否回答相关问题。 -```python -# --- 阶段 1: 写入记忆 --- -# Runner1 告诉 Agent 信息 -runner1_question = "My favorite project is Project Alpha." -user_input = types.Content(role="user", parts=[types.Part(text=runner1_question)]) - -async for event in runner1.run_async(user_id=USER_ID, session_id=session_id, new_message=user_input): - pass # 处理 Runner1 的响应 - -# 关键步骤:将会话归档到 VikingDB -completed_session = await runner1.session_service.get_session(app_name=APP_NAME, user_id=USER_ID, session_id=session_id) -root_agent.long_term_memory.add_session_to_memory(completed_session) - -# --- 阶段 2: 跨会话读取 --- -# 初始化 Runner2 (模拟新的会话或后续交互) -runner2 = Runner( - agent=root_agent, - app_name=APP_NAME, - user_id=USER_ID, - short_term_memory=short_term_memory -) - -# Runner2 提问,依赖长期记忆回答 -qa_question = "favorite project" -qa_content = types.Content(role="user", parts=[types.Part(text=qa_question)]) - -final_text = None -async for event in runner2.run_async(user_id=USER_ID, session_id=session_id, new_message=qa_content): - if event.is_final_response(): - final_text = event.content.parts[0].text.strip() -``` +=== "Python" + + ```python + # --- 阶段 1: 写入记忆 --- + # Runner1 告诉 Agent 信息 + runner1_question = "My favorite project is Project Alpha." + user_input = types.Content(role="user", parts=[types.Part(text=runner1_question)]) + + async for event in runner1.run_async(user_id=USER_ID, session_id=session_id, new_message=user_input): + pass # 处理 Runner1 的响应 + + # 关键步骤:将会话归档到 VikingDB + completed_session = await runner1.session_service.get_session(app_name=APP_NAME, user_id=USER_ID, session_id=session_id) + root_agent.long_term_memory.add_session_to_memory(completed_session) + + # --- 阶段 2: 跨会话读取 --- + # 初始化 Runner2 (模拟新的会话或后续交互) + runner2 = Runner( + agent=root_agent, + app_name=APP_NAME, + user_id=USER_ID, + short_term_memory=short_term_memory + ) + + # Runner2 提问,依赖长期记忆回答 + qa_question = "favorite project" + qa_content = types.Content(role="user", parts=[types.Part(text=qa_question)]) + + final_text = None + async for event in runner2.run_async(user_id=USER_ID, session_id=session_id, new_message=qa_content): + if event.is_final_response(): + final_text = event.content.parts[0].text.strip() + ``` + +=== "Golang" + + ```go + package main + + import ( + "context" + "log" + "strings" + + veagent "github.com/volcengine/veadk-go/agent/llmagent" + "github.com/volcengine/veadk-go/common" + vem "github.com/volcengine/veadk-go/memory" + "github.com/volcengine/veadk-go/tool/builtin_tools" + "github.com/volcengine/veadk-go/utils" + "google.golang.org/adk/agent" + "google.golang.org/adk/agent/llmagent" + "google.golang.org/adk/runner" + "google.golang.org/adk/session" + "google.golang.org/adk/tool" + "google.golang.org/genai" + ) + + func main() { + ctx := context.Background() + appName := "ve_agent" + userID := "user1111" + + // Define a tools that can search memory. + memorySearchTool, err := builtin_tools.LoadLongMemoryTool() + if err != nil { + log.Fatal(err) + return + } + + infoCaptureAgent, err := veagent.New(&veagent.Config{ + Config: llmagent.Config{ + Name: "InfoCaptureAgent", + Instruction: "Acknowledge the user's statement.", + }, + ModelName: common.DEFAULT_MODEL_AGENT_NAME, + ModelAPIBase: common.DEFAULT_MODEL_AGENT_API_BASE, + ModelAPIKey: utils.GetEnvWithDefault(common.MODEL_AGENT_API_KEY), + }) + if err != nil { + log.Printf("NewLLMAgent failed: %v", err) + return + } + + cfg := &veagent.Config{ + ModelName: common.DEFAULT_MODEL_AGENT_NAME, + ModelAPIBase: common.DEFAULT_MODEL_AGENT_API_BASE, + ModelAPIKey: utils.GetEnvWithDefault(common.MODEL_AGENT_API_KEY), + } + cfg.Name = "MemoryRecallAgent" + cfg.Instruction = "Answer the user's question. Use the 'search_past_conversations' tools if the answer might be in past conversations." + + cfg.Tools = []tool.Tool{memorySearchTool} + + memorySearchAgent, err := veagent.New(cfg) + if err != nil { + log.Printf("NewLLMAgent failed: %v", err) + return + } + + // Use all default config + //sessionService, err := vem.NewShortTermMemoryService(vem.BackendShortTermPostgreSQL, nil) + //if err != nil { + // log.Printf("NewShortTermMemoryService failed: %v", err) + // return + //} + sessionService := session.InMemoryService() + memoryService, err := vem.NewLongTermMemoryService(vem.BackendLongTermViking, nil) + if err != nil { + log.Printf("NewLongTermMemoryService failed: %v", err) + return + } + + runner1, err := runner.New(runner.Config{ + AppName: appName, + Agent: infoCaptureAgent, + SessionService: sessionService, + MemoryService: memoryService, + }) + if err != nil { + log.Fatal(err) + } + + SessionID := "session123456789" + + s, err := sessionService.Create(ctx, &session.CreateRequest{ + AppName: appName, + UserID: userID, + SessionID: SessionID, + }) + if err != nil { + log.Fatalf("sessionService.Create error: %v", err) + } + + s.Session.State() + + userInput1 := genai.NewContentFromText("My favorite project is Project Alpha.", "user") + var finalResponseText string + for event, err := range runner1.Run(ctx, userID, SessionID, userInput1, agent.RunConfig{}) { + if err != nil { + log.Printf("Agent 1 Error: %v", err) + continue + } + if event.Content != nil && !event.LLMResponse.Partial { + finalResponseText = strings.Join(textParts(event.LLMResponse.Content), "") + } + } + log.Printf("Agent 1 Response: %s\n", finalResponseText) + + // Add the completed session to the Memory Service + log.Println("\n--- Adding Session 1 to Memory ---") + resp, err := sessionService.Get(ctx, &session.GetRequest{AppName: s.Session.AppName(), UserID: s.Session.UserID(), SessionID: s.Session.ID()}) + if err != nil { + log.Fatalf("Failed to get completed session: %v", err) + } + if err := memoryService.AddSession(ctx, resp.Session); err != nil { + log.Fatalf("Failed to add session to memory: %v", err) + } + log.Println("Session added to memory.") + + log.Println("\n--- Turn 2: Recalling Information ---") + + runner2, err := runner.New(runner.Config{ + AppName: appName, + Agent: memorySearchAgent, + SessionService: sessionService, + MemoryService: memoryService, + }) + if err != nil { + log.Fatal(err) + } + + s, _ = sessionService.Create(ctx, &session.CreateRequest{ + AppName: appName, + UserID: userID, + SessionID: "session2222", + }) + + userInput2 := genai.NewContentFromText("What is my favorite project?", "user") + + var finalResponseText2 []string + for event, err := range runner2.Run(ctx, s.Session.UserID(), s.Session.ID(), userInput2, agent.RunConfig{}) { + if err != nil { + log.Printf("Agent 2 Error: %v", err) + continue + } + if event.Content != nil && !event.LLMResponse.Partial { + for _, part := range event.Content.Parts { + finalResponseText2 = append(finalResponseText2, part.Text) + } + } + } + log.Printf("Agent 2 Response: %s\n", strings.Join(finalResponseText2, "")) + + } + + func textParts(Content *genai.Content) []string { + var texts []string + for _, part := range Content.Parts { + texts = append(texts, part.Text) + } + return texts + } + ``` ### 说明 / 结果展示 diff --git a/docs/docs/memory/short-term-memory.md b/docs/docs/memory/short-term-memory.md index 02e30dee..f2d37ff7 100644 --- a/docs/docs/memory/short-term-memory.md +++ b/docs/docs/memory/short-term-memory.md @@ -15,39 +15,129 @@ title: 短期记忆 下面展示了创建和使用短期记忆: -```python -import asyncio -from veadk import Agent, Runner -from veadk.memory.short_term_memory import ShortTermMemory - -app_name = "app_short_term_1" -user_id = "user_short_term_1" -session_id = "session_short_term_1" - -agent = Agent() -short_term_memory = ShortTermMemory( - backend="local", # 指定 ShortTermMemory 的存储方式 - # 如果是 sqlite,指定数据库路径 - # local_database_path="/tmp/d_persistent_short_term_memory.db", -) -runner = Runner( - agent=agent, short_term_memory=short_term_memory, app_name=app_name, user_id=user_id -) +=== "Python" -async def main(): - response1 = await runner.run( - messages="我在 7 月 15 日购买了 20 个冰激凌", session_id=session_id + ```python + import asyncio + from veadk import Agent, Runner + from veadk.memory.short_term_memory import ShortTermMemory + + app_name = "app_short_term_1" + user_id = "user_short_term_1" + session_id = "session_short_term_1" + + agent = Agent() + short_term_memory = ShortTermMemory( + backend="local", # 指定 ShortTermMemory 的存储方式 + # 如果是 sqlite,指定数据库路径 + # local_database_path="/tmp/d_persistent_short_term_memory.db", + ) + runner = Runner( + agent=agent, short_term_memory=short_term_memory, app_name=app_name, user_id=user_id ) - print(f"response of round 1: {response1}") - response2 = await runner.run( - messages="我什么时候买了冰激凌?", session_id=session_id + async def main(): + response1 = await runner.run( + messages="我在 7 月 15 日购买了 20 个冰激凌", session_id=session_id + ) + print(f"response of round 1: {response1}") + + response2 = await runner.run( + messages="我什么时候买了冰激凌?", session_id=session_id + ) + print(f"response of round 2: {response2}") + + if __name__ == "__main__": + asyncio.run(main()) + ``` + +=== "Golang" + + ``` + package main + + import ( + "context" + "log" + "strings" + + veagent "github.com/volcengine/veadk-go/agent/llmagent" + "github.com/volcengine/veadk-go/common" + "github.com/volcengine/veadk-go/utils" + "google.golang.org/adk/agent" + "google.golang.org/adk/agent/llmagent" + "google.golang.org/adk/runner" + "google.golang.org/adk/session" + "google.golang.org/genai" ) - print(f"response of round 2: {response2}") -if __name__ == "__main__": - asyncio.run(main()) -``` + func main() { + ctx := context.Background() + appName := "ve_agent" + userID := "user1111" + + rootAgent, err := veagent.New(&veagent.Config{ + Config: llmagent.Config{ + Name: "RootAgent", + Instruction: "Acknowledge the user's statement.", + }, + ModelName: common.DEFAULT_MODEL_AGENT_NAME, + ModelAPIBase: common.DEFAULT_MODEL_AGENT_API_BASE, + ModelAPIKey: utils.GetEnvWithDefault(common.MODEL_AGENT_API_KEY), + }) + if err != nil { + log.Printf("NewLLMAgent failed: %v", err) + return + } + sessionService := session.InMemoryService() + + runner1, err := runner.New(runner.Config{ + AppName: appName, + Agent: rootAgent, + SessionService: sessionService, + }) + if err != nil { + log.Fatal(err) + } + + sessionID := "session123456789" + _, err = sessionService.Create(ctx, &session.CreateRequest{ + AppName: appName, + UserID: userID, + SessionID: sessionID, + }) + if err != nil { + log.Fatalf("sessionService.Create error: %v", err) + } + userInput1 := genai.NewContentFromText("我在 7 月 15 日购买了 20 个冰激凌。", "user") + + var finalResponseText string + for event, err := range runner1.Run(ctx, userID, sessionID, userInput1, agent.RunConfig{}) { + if err != nil { + log.Printf("Agent Error: %v", err) + continue + } + if event.Content != nil && !event.LLMResponse.Partial { + finalResponseText = strings.Join(textParts(event.LLMResponse.Content), "") + } + } + log.Printf("Agent 1 Response: %s\n", finalResponseText) + + userInput2 := genai.NewContentFromText("我什么时候买了冰激凌?", "user") + var finalResponse2Text string + for event, err := range runner1.Run(ctx, userID, sessionID, userInput2, agent.RunConfig{}) { + if err != nil { + log.Printf("Agent Error: %v", err) + continue + } + if event.Content != nil && !event.LLMResponse.Partial { + finalResponse2Text = strings.Join(textParts(event.LLMResponse.Content), "") + } + } + log.Printf("Agent 1 Response: %s\n", finalResponse2Text) + } + ``` + **示例输出** ``` diff --git a/docs/docs/tools/builtin.md b/docs/docs/tools/builtin.md index a07d0d80..e6428206 100644 --- a/docs/docs/tools/builtin.md +++ b/docs/docs/tools/builtin.md @@ -225,12 +225,90 @@ veADK 集成了以下火山引擎工具: 2. 需要配置用于 Agent 推理图像生成的模型名称 -=== "代码" +=== "Python" ```python --8<-- "examples/tools/image_generate/agent.py" ``` +=== "Golang" + + ```go + package main + + import ( + "context" + "fmt" + "log" + "os" + + "github.com/a2aproject/a2a-go/a2asrv" + "github.com/google/uuid" + veagent "github.com/volcengine/veadk-go/agent/llmagent" + "github.com/volcengine/veadk-go/common" + "github.com/volcengine/veadk-go/tool/builtin_tools" + "google.golang.org/adk/agent" + "google.golang.org/adk/agent/llmagent" + "google.golang.org/adk/artifact" + "google.golang.org/adk/cmd/launcher" + "google.golang.org/adk/cmd/launcher/full" + "google.golang.org/adk/model" + "google.golang.org/adk/session" + "google.golang.org/adk/tool" + ) + + func main() { + ctx := context.Background() + cfg := &veagent.Config{ + ModelName: common.DEFAULT_MODEL_AGENT_NAME, + ModelAPIBase: common.DEFAULT_MODEL_AGENT_API_BASE, + ModelAPIKey: os.Getenv(common.MODEL_AGENT_API_KEY), + } + cfg.Name = "image_generate_tool_agent" + cfg.Description = "Agent to generate images based on text descriptions or images." + cfg.Instruction = "I can generate images based on text descriptions or images." + cfg.AfterModelCallbacks = []llmagent.AfterModelCallback{saveReportfunc} + + imageGenerate, err := builtin_tools.NewImageGenerateTool(&builtin_tools.ImageGenerateConfig{ + ModelName: common.DEFAULT_MODEL_IMAGE_NAME, + BaseURL: common.DEFAULT_MODEL_IMAGE_API_BASE, + APIKey: os.Getenv(common.MODEL_IMAGE_API_KEY), + }) + if err != nil { + fmt.Printf("NewLLMAgent failed: %v", err) + return + } + + cfg.Tools = []tool.Tool{imageGenerate} + + sessionService := session.InMemoryService() + rootAgent, err := veagent.New(cfg) + + if err != nil { + log.Fatalf("Failed to create agent: %v", err) + } + + agentLoader, err := agent.NewMultiLoader( + rootAgent, + ) + if err != nil { + log.Fatalf("Failed to create agent loader: %v", err) + } + + artifactservice := artifact.InMemoryService() + config := &launcher.Config{ + ArtifactService: artifactservice, + SessionService: sessionService, + AgentLoader: agentLoader, + } + + l := full.NewLauncher() + if err = l.Execute(ctx, config, os.Args[1:]); err != nil { + log.Fatalf("Run failed: %v\n\n%s", err, l.CommandLineSyntax()) + } + } + ``` + === "环境变量" 环境变量列表: @@ -268,12 +346,84 @@ veADK 集成了以下火山引擎工具: 3. 需要配置用于 Agent 推理图片生成的模型名称(该用例使用了 image_generate 工具,因此需要推理图像生成模型的配置) -=== "代码" +=== "Python" ```python --8<-- "examples/tools/video_generate/agent.py" ``` +=== "Golang" + + ```go + package main + + import ( + "context" + "fmt" + "log" + "os" + + "github.com/a2aproject/a2a-go/a2asrv" + "github.com/google/uuid" + veagent "github.com/volcengine/veadk-go/agent/llmagent" + "github.com/volcengine/veadk-go/common" + "github.com/volcengine/veadk-go/tool/builtin_tools" + "google.golang.org/adk/agent" + "google.golang.org/adk/artifact" + "google.golang.org/adk/cmd/launcher" + "google.golang.org/adk/cmd/launcher/full" + "google.golang.org/adk/model" + "google.golang.org/adk/session" + "google.golang.org/adk/tool" + ) + + func main() { + ctx := context.Background() + cfg := &veagent.Config{ + ModelName: common.DEFAULT_MODEL_AGENT_NAME, + ModelAPIBase: common.DEFAULT_MODEL_AGENT_API_BASE, + ModelAPIKey: os.Getenv(common.MODEL_AGENT_API_KEY), + } + videoGenerate, err := builtin_tools.NewVideoGenerateTool(&builtin_tools.VideoGenerateConfig{ + ModelName: common.DEFAULT_MODEL_VIDEO_NAME, + BaseURL: common.DEFAULT_MODEL_VIDEO_API_BASE, + APIKey: os.Getenv(common.MODEL_VIDEO_API_KEY), + }) + if err != nil { + fmt.Printf("NewLLMAgent failed: %v", err) + return + } + + cfg.Tools = []tool.Tool{videoGenerate} + + sessionService := session.InMemoryService() + rootAgent, err := veagent.New(cfg) + + if err != nil { + log.Fatalf("Failed to create agent: %v", err) + } + + agentLoader, err := agent.NewMultiLoader( + rootAgent, + ) + if err != nil { + log.Fatalf("Failed to create agent loader: %v", err) + } + + artifactservice := artifact.InMemoryService() + config := &launcher.Config{ + ArtifactService: artifactservice, + SessionService: sessionService, + AgentLoader: agentLoader, + } + + l := full.NewLauncher() + if err = l.Execute(ctx, config, os.Args[1:]); err != nil { + log.Fatalf("Run failed: %v\n\n%s", err, l.CommandLineSyntax()) + } + } + ``` + === "环境变量" 环境变量列表: