novel-doomsday-resurgence/skills/veadk-go-skills/common/callback.md

221 lines
9.2 KiB
Markdown
Raw Permalink Normal View History

# CallBack 定义方法
## 方法说明
### 1、BeforeModelCallBack
type BeforeModelCallback func(ctx agent.CallbackContext, llmRequest *model.LLMRequest) (*model.LLMResponse, error)
BeforeModelCallback that is called before sending a request to the model.
If it returns non-nil LLMResponse or error, the actual model call is skipped
and the returned response/error is used.
### 2、AfterModelCallback
type AfterModelCallback func(ctx agent.CallbackContext, llmResponse *model.LLMResponse, llmResponseError error) (*model.LLMResponse, error)
AfterModelCallback that is called after receiving a response from the model.
If it returns non-nil LLMResponse or error, the actual model response/error
is replaced with the returned response/error.
### 3、BeforeToolCallback
type BeforeToolCallback func(ctx tool.Context, tool tool.Tool, args map[string]any) (map[string]any, error)
BeforeToolCallback is executed before a tool's Run method.
Callbacks are executed in the order they are provided.
If a callback returns a non-nil result or an error:
- execution of remaining callbacks stops
- the actual tool call is skipped
- the returned result is used as the tool result
To modify tool arguments and still run the tool,
update args in place and return (nil, nil).
### 4、AfterToolCallback
type AfterToolCallback func(ctx tool.Context, tool tool.Tool, args, result map[string]any, err error) (map[string]any, error)
AfterToolCallback is a function type executed after a tool's Run method has completed,
regardless of whether the tool returned a result or an error.
Callbacks are executed in the order they are provided.
If a callback returns a non-nil result or an error:
- execution of remaining callbacks stops
- the returned result and/or error is used as the final tool output
## callback方法示例
### 1、BeforeModelCallBack 代码示例
何时触发: 在LlmAgent流程中向 LLM 发送请求之前调用。
用途: 允许检查和修改发送给 LLM 的请求。用例包括添加动态指令、基于状态注入少量示例、修改模型配置、实现防护机制 (如亵渎过滤器) 或实现请求级缓存。
返回值效果: 如果回调返回 nilLLM 继续其正常工作流程。如果回调返回 LlmResponse 对象,则跳过对 LLM 的调用。返回的 LlmResponse 直接使用,就像它来自模型一样。这对于实现防护栏或缓存非常强大。
```go
func onBeforeModel(ctx agent.CallbackContext, req *model.LLMRequest) (*model.LLMResponse, error) {
log.Printf("[Callback] BeforeModel triggered for agent %q.", ctx.AgentName())
// Modification Example: Add a prefix to the system instruction.
if req.Config.SystemInstruction != nil {
prefix := "[Modified by Callback] "
// This is a simplified example; production code might need deeper checks.
if len(req.Config.SystemInstruction.Parts) > 0 {
req.Config.SystemInstruction.Parts[0].Text = prefix + req.Config.SystemInstruction.Parts[0].Text
} else {
req.Config.SystemInstruction.Parts = append(req.Config.SystemInstruction.Parts, &genai.Part{Text: prefix})
}
log.Printf("[Callback] Modified system instruction.")
}
// Skip Example: Check for "BLOCK" in the user's prompt.
for _, content := range req.Contents {
for _, part := range content.Parts {
if strings.Contains(strings.ToUpper(part.Text), "BLOCK") {
log.Println("[Callback] 'BLOCK' keyword found. Skipping LLM call.")
return &model.LLMResponse{
Content: &genai.Content{
Parts: []*genai.Part{{Text: "LLM call was blocked by before_model_callback."}},
Role: "model",
},
}, nil
}
}
}
log.Println("[Callback] Proceeding with LLM call.")
return nil, nil
}
rootAgent, err := veagent.New(&veagent.Config{
Config: llmagent.Config{
Name: "...",
Description: "...",
Instruction: "...",
BeforeModelCallbacks:[]llmagent.BeforeModelCallback{
onBeforeModel,
},
},
})
```
### 2、AfterModelCallBack 代码示例
何时触发: 在从 LLM 接收到响应 (LlmResponse) 之后,在调用智能体进一步处理之前调用。
用途: 允许检查或修改原始 LLM 响应。用例包括:
记录模型输出,
重新格式化响应,
审查模型生成的敏感信息,
从 LLM 响应中解析结构化数据并将其存储在callback_context.state中
或处理特定错误代码。
```go
func onAfterModel(ctx agent.CallbackContext, resp *model.LLMResponse, respErr error) (*model.LLMResponse, error) {
log.Printf("[Callback] AfterModel triggered for agent %q.", ctx.AgentName())
if respErr != nil {
log.Printf("[Callback] Model returned an error: %v. Passing it through.", respErr)
return nil, respErr
}
if resp == nil || resp.Content == nil || len(resp.Content.Parts) == 0 {
log.Println("[Callback] Response is nil or has no parts, nothing to process.")
return nil, nil
}
// Check for function calls and pass them through without modification.
if resp.Content.Parts[0].FunctionCall != nil {
log.Println("[Callback] Response is a function call. No modification.")
return nil, nil
}
originalText := resp.Content.Parts[0].Text
// Use a case-insensitive regex with word boundaries to find "joke".
re := regexp.MustCompile(`(?i)\bjoke\b`)
if !re.MatchString(originalText) {
log.Println("[Callback] 'joke' not found. Passing original response through.")
return nil, nil
}
log.Println("[Callback] 'joke' found. Modifying response.")
// Use a replacer function to handle capitalization.
modifiedText := re.ReplaceAllStringFunc(originalText, func(s string) string {
if strings.ToUpper(s) == "JOKE" {
if s == "Joke" {
return "Funny story"
}
return "funny story"
}
return s // Should not be reached with this regex, but it's safe.
})
resp.Content.Parts[0].Text = modifiedText
return resp, nil
}
```
### 3、BeforeToolCallback 代码示例
何时触发: 在调用特定工具的run_async方法之前在 LLM 为其生成函数调用之后调用。
用途: 允许检查和修改工具参数,在执行前执行授权检查,记录工具使用尝试,或实现工具级缓存。
返回值效果:
如果回调返回 nil工具方法将使用可能修改的args 执行。
如果返回map工具方法将被跳过。返回的字典直接用作工具调用的结果。这对于缓存或覆盖工具行为很有用。
```go
func onBeforeTool(ctx tool.Context, t tool.Tool, args map[string]any) (map[string]any, error) {
log.Printf("[Callback] BeforeTool triggered for tool %q in agent %q.", t.Name(), ctx.AgentName())
log.Printf("[Callback] Original args: %v", args)
if t.Name() == "getCapitalCity" {
if country, ok := args["country"].(string); ok {
if strings.ToLower(country) == "canada" {
log.Println("[Callback] Detected 'Canada'. Modifying args to 'France'.")
args["country"] = "France"
return args, nil // Proceed with modified args
} else if strings.ToUpper(country) == "BLOCK" {
log.Println("[Callback] Detected 'BLOCK'. Skipping tool execution.")
// Skip tool and return a custom result.
return map[string]any{"result": "Tool execution was blocked by before_tool_callback."}, nil
}
}
}
log.Println("[Callback] Proceeding with original or previously modified args.")
return nil, nil // Proceed with original args
}
```
### 4、AfterToolCallback 代码示例
何时触发: 在工具的执行方法成功完成后立即调用。
用途: 允许在将工具结果发送回 LLM(可能在摘要后) 之前对其进行检查和修改。适用于记录工具结果、后处理或格式化结果,或将结果的特定部分保存到会话状态。
返回值效果:
如果回调返回 nil使用原始的 tool_response。
如果返回新map它替换原始的 tool_response。这允许修改或过滤 LLM 看到的结果。
```go
func onAfterTool(ctx tool.Context, t tool.Tool, args map[string]any, result map[string]any, err error) (map[string]any, error) {
log.Printf("[Callback] AfterTool triggered for tool %q in agent %q.", t.Name(), ctx.AgentName())
log.Printf("[Callback] Original result: %v", result)
if err != nil {
log.Printf("[Callback] Tool run produced an error: %v. Passing through.", err)
return nil, err
}
if t.Name() == "getCapitalCity" {
if originalResult, ok := result["result"].(string); ok && originalResult == "Washington, D.C." {
log.Println("[Callback] Detected 'Washington, D.C.'. Modifying tool response.")
modifiedResult := make(map[string]any)
for k, v := range result {
modifiedResult[k] = v
}
modifiedResult["result"] = fmt.Sprintf("%s (Note: This is the capital of the USA).", originalResult)
modifiedResult["note_added_by_callback"] = true
return modifiedResult, nil
}
}
log.Println("[Callback] Passing original tool response through.")
return nil, nil
}
```