feat: add examples for adk (#120)
parent
3a94b9ab0d
commit
bbbae09319
@ -0,0 +1,21 @@
|
||||
# Eino ADK Examples
|
||||
|
||||
This directory provides examples for Eino ADK:
|
||||
|
||||
- Agent
|
||||
- `helloworld`: simple hello-world chat agent.
|
||||
- `intro`
|
||||
- `chatmodel`: example about using `ChatModelAgent` with interrupt.
|
||||
- `custom`: shows how to implement an agent which meets the definition of ADK.
|
||||
- `workflow`: examples about using `Loop` / `Parallel` / `Sequential` agent.
|
||||
- `session`: shows how to pass data and state across agents by using session.
|
||||
- `transfer`: shows transfer ability by using ChatModelAgent.
|
||||
- `multiagent`
|
||||
- `plan-execute-replan`: basic example of plan-execute-replan agent.
|
||||
- `supervisor`: basic example of supervisor agent.
|
||||
- `layered-supervisor`: another example of supervisor agent, which set a supervisor agent as sub-agent of another supervisor agent.
|
||||
- `integration-project-manager`: another example of using supervisor agent.
|
||||
- `common`: utils.
|
||||
|
||||
|
||||
Additionally, you can enable [coze-loop](https://github.com/coze-dev/coze-loop) trace for examples, see .example.env for keys.
|
||||
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2025 CloudWeGo Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/cloudwego/eino/adk"
|
||||
"github.com/cloudwego/eino/schema"
|
||||
|
||||
"github.com/cloudwego/eino-ext/components/model/openai"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx := context.Background()
|
||||
|
||||
// 初始化模型
|
||||
model, err := openai.NewChatModel(ctx, &openai.ChatModelConfig{
|
||||
APIKey: os.Getenv("OPENAI_API_KEY"),
|
||||
Model: os.Getenv("OPENAI_MODEL"),
|
||||
BaseURL: os.Getenv("OPENAI_BASE_URL"),
|
||||
ByAzure: func() bool {
|
||||
return os.Getenv("OPENAI_BY_AZURE") == "true"
|
||||
}(),
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// 创建 ChatModelAgent
|
||||
agent, err := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
|
||||
Name: "hello_agent",
|
||||
Description: "A friendly greeting assistant",
|
||||
Instruction: "You are a friendly assistant. Please respond to the user in a warm tone.",
|
||||
Model: model,
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// 创建 Runner
|
||||
runner := adk.NewRunner(ctx, adk.RunnerConfig{
|
||||
Agent: agent,
|
||||
EnableStreaming: true,
|
||||
})
|
||||
|
||||
// 执行对话
|
||||
input := []adk.Message{
|
||||
schema.UserMessage("Hello, please introduce yourself."),
|
||||
}
|
||||
|
||||
events := runner.Run(ctx, input)
|
||||
for {
|
||||
event, ok := events.Next()
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
|
||||
if event.Err != nil {
|
||||
log.Printf("错误: %v", event.Err)
|
||||
break
|
||||
}
|
||||
|
||||
if msg, err := event.Output.MessageOutput.GetMessage(); err == nil {
|
||||
fmt.Printf("Agent: %s\n", msg.Content)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2025 CloudWeGo Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/cloudwego/eino-examples/adk/common/prints"
|
||||
"github.com/cloudwego/eino-examples/adk/common/trace"
|
||||
"github.com/cloudwego/eino-examples/adk/intro/workflow/parallel/subagents"
|
||||
"github.com/cloudwego/eino/adk"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx := context.Background()
|
||||
|
||||
traceCloseFn, startSpanFn := trace.AppendCozeLoopCallbackIfConfigured(ctx)
|
||||
defer traceCloseFn(ctx)
|
||||
|
||||
a, err := adk.NewParallelAgent(ctx, &adk.ParallelAgentConfig{
|
||||
Name: "DataCollectionAgent",
|
||||
Description: "Data Collection Agent could collect data from multiple sources.",
|
||||
SubAgents: []adk.Agent{
|
||||
subagents.NewStockDataCollectionAgent(),
|
||||
subagents.NewNewsDataCollectionAgent(),
|
||||
subagents.NewSocialMediaInfoCollectionAgent(),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
query := "give me today's market research"
|
||||
ctx, endSpanFn := startSpanFn(ctx, "layered-supervisor", query)
|
||||
|
||||
runner := adk.NewRunner(ctx, adk.RunnerConfig{
|
||||
EnableStreaming: true, // you can disable streaming here
|
||||
Agent: a,
|
||||
})
|
||||
|
||||
iter := runner.Query(ctx, query)
|
||||
|
||||
var lastMessage adk.Message
|
||||
|
||||
for {
|
||||
event, ok := iter.Next()
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
if event.Err != nil {
|
||||
fmt.Printf("Error: %v\n", event.Err)
|
||||
break
|
||||
}
|
||||
|
||||
prints.Event(event)
|
||||
if event.Output != nil {
|
||||
lastMessage, _, err = adk.GetMessage(event)
|
||||
}
|
||||
}
|
||||
|
||||
endSpanFn(ctx, lastMessage)
|
||||
}
|
||||
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2025 CloudWeGo Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package subagents
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
|
||||
"github.com/cloudwego/eino/adk"
|
||||
|
||||
"github.com/cloudwego/eino-examples/adk/common/model"
|
||||
)
|
||||
|
||||
func NewStockDataCollectionAgent() adk.Agent {
|
||||
a, err := adk.NewChatModelAgent(context.Background(), &adk.ChatModelAgentConfig{
|
||||
Name: "StockDataCollectionAgent",
|
||||
Description: "The Stock Data Collection Agent is designed to gather real-time and historical stock market data from various reliable sources. It provides comprehensive information including stock prices, trading volumes, market trends, and financial indicators to support investment analysis and decision-making.",
|
||||
Instruction: `You are a Stock Data Collection Agent. Your role is to:
|
||||
|
||||
- Collect accurate and up-to-date stock market data from trusted sources.
|
||||
- Retrieve information such as stock prices, trading volumes, historical trends, and relevant financial indicators.
|
||||
- Ensure data completeness and reliability.
|
||||
- Format the collected data clearly for further analysis or user queries.
|
||||
- Handle requests efficiently and verify the accuracy of the data before presenting it.
|
||||
- Maintain professionalism and clarity in communication.`,
|
||||
Model: model.NewChatModel(),
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
func NewNewsDataCollectionAgent() adk.Agent {
|
||||
a, err := adk.NewChatModelAgent(context.Background(), &adk.ChatModelAgentConfig{
|
||||
Name: "NewsDataCollectionAgent",
|
||||
Description: "The News Data Collection Agent specializes in aggregating news articles and updates from multiple reputable news outlets. It focuses on gathering timely and relevant information across various topics to keep users informed and support data-driven insights.",
|
||||
Instruction: `You are a News Data Collection Agent. Your responsibilities include:
|
||||
|
||||
- Aggregating news articles and updates from diverse and credible news sources.
|
||||
- Filtering and organizing news based on relevance, timeliness, and user interests.
|
||||
- Providing summaries or full content as required.
|
||||
- Ensuring the accuracy and authenticity of the collected news data.
|
||||
- Presenting information in a clear, concise, and unbiased manner.
|
||||
- Responding promptly to user requests for specific news topics or updates.`,
|
||||
Model: model.NewChatModel(),
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
func NewSocialMediaInfoCollectionAgent() adk.Agent {
|
||||
a, err := adk.NewChatModelAgent(context.Background(), &adk.ChatModelAgentConfig{
|
||||
Name: "SocialMediaInformationCollectionAgent",
|
||||
Description: "The Social Media Information Collection Agent is tasked with gathering data from various social media platforms. It collects user-generated content, trends, sentiments, and discussions to provide insights into public opinion and emerging topics.",
|
||||
Instruction: `You are a Social Media Information Collection Agent. Your tasks are to:
|
||||
|
||||
- Collect relevant and up-to-date information from multiple social media platforms.
|
||||
- Monitor trends, user sentiments, and public discussions related to specified topics.
|
||||
- Ensure the data collected respects privacy and platform policies.
|
||||
- Organize and summarize the information to highlight key insights.
|
||||
- Provide clear and objective reports based on the social media data.
|
||||
- Communicate findings in a user-friendly and professional manner.`,
|
||||
Model: model.NewChatModel(),
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return a
|
||||
}
|
||||
@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright 2025 CloudWeGo Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/cloudwego/eino-ext/components/model/openai"
|
||||
"github.com/cloudwego/eino/adk"
|
||||
"github.com/cloudwego/eino/adk/prebuilt/supervisor"
|
||||
"github.com/cloudwego/eino/components/tool"
|
||||
"github.com/cloudwego/eino/compose"
|
||||
|
||||
"github.com/cloudwego/eino-examples/adk/common/prints"
|
||||
"github.com/cloudwego/eino-examples/adk/multiagent/integration-project-manager/agents"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx := context.Background()
|
||||
|
||||
// Init chat model for agents
|
||||
tcm, err := openai.NewChatModel(ctx, &openai.ChatModelConfig{
|
||||
APIKey: os.Getenv("OPENAI_API_KEY"),
|
||||
Model: os.Getenv("OPENAI_MODEL"),
|
||||
BaseURL: os.Getenv("OPENAI_BASE_URL"),
|
||||
ByAzure: func() bool {
|
||||
return os.Getenv("OPENAI_BY_AZURE") == "true"
|
||||
}(),
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Init research agent
|
||||
researchAgent, err := agents.NewResearchAgent(ctx, tcm)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Init code agent
|
||||
codeAgent, err := agents.NewCodeAgent(ctx, tcm)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Init technical agent
|
||||
reviewAgent, err := agents.NewReviewAgent(ctx, tcm)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Init project manager agent
|
||||
s, err := agents.NewProjectManagerAgent(ctx, tcm)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Combine agents into ADK supervisor pattern
|
||||
// Supervisor: project manager
|
||||
// Sub-agents: researcher / coder / reviewer
|
||||
supervisorAgent, err := supervisor.New(ctx, &supervisor.Config{
|
||||
Supervisor: s,
|
||||
SubAgents: []adk.Agent{researchAgent, codeAgent, reviewAgent},
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Init Agent runner
|
||||
runner := adk.NewRunner(ctx, adk.RunnerConfig{
|
||||
Agent: supervisorAgent,
|
||||
EnableStreaming: true,
|
||||
CheckPointStore: newInMemoryStore(),
|
||||
})
|
||||
|
||||
// Replace it with your own query
|
||||
// When using the following query, researchAgent will interrupt and prompt the user to input the specific research subject via stdin.
|
||||
query := "please give me a report about advantages of "
|
||||
checkpointID := "1"
|
||||
|
||||
// The researchAgent may require users to input information multiple times
|
||||
// Therefore, the following flags, "interrupted" and "finished," are used to support multiple interruptions and resumptions.
|
||||
interrupted := false
|
||||
finished := false
|
||||
|
||||
for !finished {
|
||||
var iter *adk.AsyncIterator[*adk.AgentEvent]
|
||||
|
||||
if !interrupted {
|
||||
iter = runner.Query(ctx, query, adk.WithCheckPointID(checkpointID))
|
||||
} else {
|
||||
scanner := bufio.NewScanner(os.Stdin)
|
||||
fmt.Print("\ninput additional context for web search: ")
|
||||
scanner.Scan()
|
||||
fmt.Println()
|
||||
nInput := scanner.Text()
|
||||
|
||||
iter, err = runner.Resume(ctx, checkpointID, adk.WithToolOptions([]tool.Option{agents.WithNewInput(nInput)}))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
interrupted = false
|
||||
|
||||
for {
|
||||
event, ok := iter.Next()
|
||||
if !ok {
|
||||
if !interrupted {
|
||||
finished = true
|
||||
}
|
||||
break
|
||||
}
|
||||
if event.Err != nil {
|
||||
log.Fatal(event.Err)
|
||||
}
|
||||
if event.Action != nil {
|
||||
if event.Action.Interrupted != nil {
|
||||
interrupted = true
|
||||
}
|
||||
if event.Action.Exit {
|
||||
finished = true
|
||||
}
|
||||
}
|
||||
prints.Event(event)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func newInMemoryStore() compose.CheckPointStore {
|
||||
return &inMemoryStore{
|
||||
mem: map[string][]byte{},
|
||||
}
|
||||
}
|
||||
|
||||
type inMemoryStore struct {
|
||||
mem map[string][]byte
|
||||
}
|
||||
|
||||
func (i *inMemoryStore) Set(ctx context.Context, key string, value []byte) error {
|
||||
i.mem[key] = value
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *inMemoryStore) Get(ctx context.Context, key string) ([]byte, bool, error) {
|
||||
v, ok := i.mem[key]
|
||||
return v, ok, nil
|
||||
}
|
||||
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2025 CloudWeGo Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package agents
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/cloudwego/eino/adk"
|
||||
"github.com/cloudwego/eino/components/model"
|
||||
"github.com/cloudwego/eino/components/tool"
|
||||
"github.com/cloudwego/eino/components/tool/utils"
|
||||
"github.com/cloudwego/eino/compose"
|
||||
)
|
||||
|
||||
func NewCodeAgent(ctx context.Context, tcm model.ToolCallingChatModel) (adk.Agent, error) {
|
||||
type RAGInput struct {
|
||||
Query string `json:"query" jsonschema:"description=query for search"`
|
||||
Context *string `json:"context" jsonschema:"description=user input context"`
|
||||
}
|
||||
type RAGOutput struct {
|
||||
Documents []string `json:"documents"`
|
||||
}
|
||||
knowledgeBaseTool, err := utils.InferTool(
|
||||
"knowledge_base",
|
||||
"knowledge base which could answer common questions, provide specific reasons for answers, and improve accuracy",
|
||||
func(ctx context.Context, input *RAGInput) (output *RAGOutput, err error) {
|
||||
// replace it with real knowledge base search
|
||||
if input.Query == "" {
|
||||
return nil, fmt.Errorf("RAG Input query is required")
|
||||
}
|
||||
|
||||
return &RAGOutput{
|
||||
[]string{
|
||||
"Q: What is the difference between a list and a tuple in Python?\nA: A list is mutable, meaning you can modify its elements after creation, while a tuple is immutable and cannot be changed once created. Lists use square brackets [], tuples use parentheses ().",
|
||||
"Q: How do you handle exceptions in Java?\nA: You handle exceptions in Java using try-catch blocks. Code that might throw an exception is placed inside the try block, and the catch block handles the exception. Optionally, a finally block can be used for cleanup.",
|
||||
"Q: What is the purpose of the async and await keywords in JavaScript?\nA: async marks a function as asynchronous, allowing it to return a Promise. await pauses the execution of an async function until the Promise resolves, enabling easier asynchronous code writing.",
|
||||
"Q: How can you optimize SQL queries for better performance?\nA: Common optimizations include creating indexes on frequently queried columns, avoiding SELECT *, using JOINs efficiently, and analyzing query execution plans to identify bottlenecks.",
|
||||
"Q: What is dependency injection and why is it useful?\nA: Dependency injection is a design pattern where an object receives its dependencies from an external source rather than creating them itself. It promotes loose coupling, easier testing, and better code maintainability.",
|
||||
},
|
||||
}, nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
|
||||
Name: "CodeAgent",
|
||||
Description: "The CodeAgent specializes in generating high-quality code by leveraging a knowledge base as a tool. It recalls relevant knowledge and best practices to produce efficient, maintainable, and accurate code solutions tailored to the project requirements.",
|
||||
Instruction: `You are the CodeAgent. Your responsibilities include:
|
||||
|
||||
- Generating high-quality, efficient, and maintainable code based on the project requirements.
|
||||
- Utilizing a knowledge base tool to recall relevant coding standards, patterns, and best practices.
|
||||
- Ensuring the code is clear, well-documented, and meets the specified functionality.
|
||||
- Reviewing related knowledge to enhance the accuracy and quality of your code.
|
||||
- Communicating your coding decisions and providing explanations when necessary.
|
||||
- Responding promptly and professionally to user requests or clarifications.
|
||||
|
||||
Tool handling:
|
||||
When the user's question is vague or exceeds the scope of your answer, please use the knowledge_base tool to recall relevant results from the knowledge base and provide accurate answers based on the results.
|
||||
`,
|
||||
Model: tcm,
|
||||
ToolsConfig: adk.ToolsConfig{
|
||||
ToolsNodeConfig: compose.ToolsNodeConfig{
|
||||
Tools: []tool.BaseTool{knowledgeBaseTool},
|
||||
},
|
||||
},
|
||||
MaxIterations: 3,
|
||||
})
|
||||
}
|
||||
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2025 CloudWeGo Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package agents
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
|
||||
"github.com/cloudwego/eino/adk"
|
||||
"github.com/cloudwego/eino/components/model"
|
||||
)
|
||||
|
||||
func NewProjectManagerAgent(ctx context.Context, tcm model.ToolCallingChatModel) (adk.Agent, error) {
|
||||
a, err := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
|
||||
Name: "ProjectManagerAgent",
|
||||
Description: "The ProjectManagerAgent acts as the supervisor and coordinator of the project workflow. It dynamically routes and coordinates multiple sub-agents responsible for different dimensions of the work, such as research, coding, and review, based on user inputs and project needs.",
|
||||
Instruction: `You are the ProjectManagerAgent. Your role is to:
|
||||
|
||||
- Supervise and coordinate multiple specialized three sub-agents: ResearchAgent, CodeAgent, ReviewAgent.
|
||||
- ResearchAgent: assign this agent when you need to conduct research and generate feasible solutions.
|
||||
- CodeAgent: assign this agent when you need generate high-quality code.
|
||||
- ReviewAgent: assign this agent when you need evaluate research or coding results.
|
||||
- Dynamically route tasks and user inputs to the appropriate sub-agent based on the current project requirements.
|
||||
- Monitor the progress and outputs of each sub-agent to ensure alignment with project goals.
|
||||
- Facilitate communication and collaboration among sub-agents to optimize workflow efficiency.
|
||||
- Provide clear updates and summaries to the user regarding project status and next steps.
|
||||
- Maintain a professional, organized, and proactive approach to project management.
|
||||
`,
|
||||
Model: tcm,
|
||||
Exit: &adk.ExitTool{},
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return a, nil
|
||||
}
|
||||
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2025 CloudWeGo Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package agents
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/cloudwego/eino/adk"
|
||||
"github.com/cloudwego/eino/components/model"
|
||||
"github.com/cloudwego/eino/components/tool"
|
||||
"github.com/cloudwego/eino/components/tool/utils"
|
||||
"github.com/cloudwego/eino/compose"
|
||||
)
|
||||
|
||||
func NewResearchAgent(ctx context.Context, tcm model.ToolCallingChatModel) (adk.Agent, error) {
|
||||
type webSearchInput struct {
|
||||
CurrentContext string `json:"current_context" jsonschema:"description=current context for web search"`
|
||||
}
|
||||
type webSearchOutput struct {
|
||||
Result []string
|
||||
}
|
||||
webSearchTool, err := utils.InferTool(
|
||||
"web_search",
|
||||
"web search tool",
|
||||
func(ctx context.Context, input *webSearchInput) (output *webSearchOutput, err error) {
|
||||
// replace it with real web search tool
|
||||
if input.CurrentContext == "" {
|
||||
return nil, fmt.Errorf("web search input is required")
|
||||
}
|
||||
return &webSearchOutput{}, nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
|
||||
Name: "ResearchAgent",
|
||||
Description: "The ResearchAgent is responsible for conducting research and generating feasible solutions. It supports interruption to receive additional contextual information from the user, which helps improve the accuracy and relevance of the research outcomes. It utilizes web search tools to gather up-to-date information.",
|
||||
Instruction: `You are the ResearchAgent. Your role is to:
|
||||
|
||||
- Conduct thorough research on the given topic or problem.
|
||||
- Generate feasible and well-informed solutions based on your findings.
|
||||
- Support interruptions by accepting additional context or information from the user at any time to refine your research.
|
||||
- Use web search tools effectively to gather relevant and current data.
|
||||
- Communicate your research results clearly and logically.
|
||||
- Ask clarifying questions if needed to improve the quality of your research.
|
||||
- Maintain a professional and helpful tone throughout the interaction.
|
||||
|
||||
Tool Handling:
|
||||
- When you think the input information is insufficient to support the research, please use ask_for_clarification tool to ask the user to supplement the context.
|
||||
- If context is fulfilled, you can use the web_search tool to obtain more data from internet.
|
||||
`,
|
||||
Model: tcm,
|
||||
ToolsConfig: adk.ToolsConfig{
|
||||
ToolsNodeConfig: compose.ToolsNodeConfig{
|
||||
Tools: []tool.BaseTool{webSearchTool, newAskForClarificationTool()},
|
||||
},
|
||||
},
|
||||
MaxIterations: 5,
|
||||
})
|
||||
}
|
||||
|
||||
type askForClarificationOptions struct {
|
||||
NewInput *string
|
||||
}
|
||||
|
||||
func WithNewInput(input string) tool.Option {
|
||||
return tool.WrapImplSpecificOptFn(func(t *askForClarificationOptions) {
|
||||
t.NewInput = &input
|
||||
})
|
||||
}
|
||||
|
||||
type AskForClarificationInput struct {
|
||||
Question string `json:"question" jsonschema:"description=The specific question you want to ask the user to get the missing information"`
|
||||
}
|
||||
|
||||
func newAskForClarificationTool() tool.InvokableTool {
|
||||
t, err := utils.InferOptionableTool(
|
||||
"ask_for_clarification",
|
||||
"Call this tool when the user's request is ambiguous or lacks the necessary information to proceed. Use it to ask a follow-up question to get the details you need, such as the book's genre, before you can use other tools effectively.",
|
||||
func(ctx context.Context, input *AskForClarificationInput, opts ...tool.Option) (output string, err error) {
|
||||
o := tool.GetImplSpecificOptions[askForClarificationOptions](nil, opts...)
|
||||
if o.NewInput == nil {
|
||||
return "", compose.NewInterruptAndRerunErr(input.Question)
|
||||
}
|
||||
output = *o.NewInput
|
||||
o.NewInput = nil
|
||||
return output, nil
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return t
|
||||
}
|
||||
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2025 CloudWeGo Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package agents
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/cloudwego/eino/adk"
|
||||
"github.com/cloudwego/eino/components/model"
|
||||
)
|
||||
|
||||
func NewReviewAgent(ctx context.Context, tcm model.ToolCallingChatModel) (adk.Agent, error) {
|
||||
// these sub-agents don't need description because they'll be set in a fixed workflow.
|
||||
questionAnalysisAgent, err := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
|
||||
Name: "question_analysis_agent",
|
||||
Description: "question analysis agent",
|
||||
Instruction: `You are the Question Analysis Agent. Your responsibilities include:
|
||||
|
||||
- Analyzing the given research or coding results to identify critical questions and evaluation criteria.
|
||||
- Breaking down complex issues into clear, manageable components.
|
||||
- Highlighting potential problems or areas of concern.
|
||||
- Preparing a structured framework to guide the subsequent review generation.
|
||||
- Ensuring thorough understanding of the content before passing it on.`,
|
||||
Model: tcm,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
generateReviewAgent, err := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
|
||||
Name: "generate_review_agent",
|
||||
Description: "generate review agent",
|
||||
Instruction: `You are the Generate Review Agent. Your role is to:
|
||||
|
||||
- Produce comprehensive and balanced reviews based on the question analysis.
|
||||
- Highlight strengths, weaknesses, and areas for improvement.
|
||||
- Provide constructive and actionable feedback.
|
||||
- Maintain objectivity and clarity in your evaluations.
|
||||
- Prepare the review content for validation in the next step.`,
|
||||
Model: tcm,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
reviewValidationAgent, err := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
|
||||
Name: "review_validation_agent",
|
||||
Description: "review validation agent",
|
||||
Instruction: `You are the Review Validation Agent. Your tasks are to:
|
||||
|
||||
- Validate the generated review for accuracy, coherence, and fairness.
|
||||
- Check for logical consistency and completeness.
|
||||
- Identify any biases or errors and suggest corrections.
|
||||
- Confirm that the review aligns with the original analysis and project goals.
|
||||
- Approve the review for final presentation or request revisions if necessary.`,
|
||||
Model: tcm,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return adk.NewSequentialAgent(ctx, &adk.SequentialAgentConfig{
|
||||
Name: "ReviewAgent",
|
||||
Description: "The ReviewAgent is responsible for evaluating research and coding results through a sequential workflow. It orchestrates three key steps—question analysis, review generation, and review validation—to provide well-reasoned assessments that support project management decisions.",
|
||||
SubAgents: []adk.Agent{questionAnalysisAgent, generateReviewAgent, reviewValidationAgent},
|
||||
})
|
||||
}
|
||||
Loading…
Reference in New Issue