ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

在 langchaingo 中组合使用 OpenAI Function Calling 与流式响应:以 GPT-4 Turbo 天气查询示例为例

在 langchaingo 中组合使用 OpenAI Function Calling 与流式响应:以 GPT-4 Turbo 天气查询示例为例 在 langchaingo 中组合使用 OpenAI Function Calling 与流式响应以 GPT-4 Turbo 天气查询示例为例【免费下载链接】langchaingoLangChain for Go, the easiest way to write LLM-based programs in Go项目地址: https://gitcode.com/GitHub_Trending/la/langchaingo导读本篇技术指南以 langchaingo 官方示例 openai-function-call-streaming-example 为主线讲解如何在一个 Go 程序中同时启用 OpenAI 的函数调用Function Calling与流式输出Streaming既能通过llms.WithTools向模型注册天气查询等外部工具又能借助llms.WithStreamingFunc逐块实时打印模型生成内容并在响应到达后从ContentResponse.Choices[0].FuncCall检测模型发起的函数调用。读完本文你将掌握 langchaingo 中「工具声明 → 请求组装 → 流式回调 → 函数调用检测」的完整调用链并理解其背后的类型定义与底层实现原理。示例概览这个程序做了什么示例文件 openai_function_call_example.go 的核心流程可拆解为五个步骤模型初始化通过openai.New(openai.WithModel(gpt-4-turbo))连接 OpenAI 的 GPT-4 Turbo 模型工具定义声明三个可供模型调用的函数工具——getCurrentWeather获取某地当前天气、getTomorrowWeather获取某地预报天气、getSuggestedPrompts根据用户输入生成相关建议提示词用户查询向模型发送问题 What is the weather like in Boston?流式响应注册流式回调函数把模型每次生成的文本块实时打印到控制台函数调用检测请求完成后检查resp.Choices[0].FuncCall若模型决定调用函数则打印该调用信息。整体设计体现了 langchaingo 的一个典型用法把 LLM 当作决策者让它通过工具声明决定是否调用外部能力同时以流式方式观察其生成过程。环境准备与依赖示例位于examples/openai-function-call-streaming-example目录其 go.mod 声明module github.com/tmc/langchaingo/examples/openai-function-call-streaming-example go 1.24.3 require github.com/tmc/langchaingo v0.1.14-pre.4运行前需设置 OpenAI API Key。langchaingo 的 OpenAI 实现会从环境变量读取凭证缺少时返回错误missing the OpenAI API key, set it in the OPENAI_API_KEY environment variable见 llms/openai/llm.go 中的tokenEnvVarName逻辑。启动方式export OPENAI_API_KEYyour_api_key_here go run openai_function_call_example.go模型初始化与请求组装创建模型实例llm, err : openai.New(openai.WithModel(gpt-4-turbo)) if err ! nil { log.Fatal(err) }openai.WithModel用于指定模型名称。从 llms/openai/openaillm.go 的实现可以看到每次请求时opts.Model会优先覆盖实例默认模型effectiveModel : opts.Model; if effectiveModel { effectiveModel o.model }也就是说模型既可以在创建实例时指定也可以在单次请求中通过 CallOption 覆盖。构造用户消息ctx : context.Background() resp, err : llm.GenerateContent(ctx, []llms.MessageContent{ llms.TextParts(llms.ChatMessageTypeHuman, What is the weather like in Boston?), }, llms.WithStreamingFunc(func(ctx context.Context, chunk []byte) error { fmt.Printf(Received chunk: %s\n, chunk) return nil }), llms.WithTools(tools))这里用到了三个关键 APIllms.MessageContent一条发给模型的聊天消息包含Role消息角色与Parts内容片段序列定义于 llms/generatecontent.gollms.TextParts便捷构造函数将若干字符串打包成指定角色的MessageContentllms/generatecontent.go。其中llms.ChatMessageTypeHuman表示人类消息其值为human见 llms/chat_messages.go同一枚举还包含ai、system、tool等角色llms.GenerateContentlangchaingo 各模型统一实现的内容生成入口签名兼容多模态文本、图片 URL、二进制内容等均可作为 Part。流式响应WithStreamingFunc 的原理回调注册llms.WithStreamingFunc定义于 llms/options.go// WithStreamingFunc specifies the streaming function to use. func WithStreamingFunc(streamingFunc func(ctx context.Context, chunk []byte) error) CallOption {它接收一个回调函数每次模型产出新的文本块chunk时被调用一次。示例中的实现仅做打印llms.WithStreamingFunc(func(ctx context.Context, chunk []byte) error { fmt.Printf(Received chunk: %s\n, chunk) return nil }),底层流转从源码结构看流式响应的底层链路为llms.GenerateContent解析 CallOption 后将opts.StreamingFunc传递给 OpenAI 客户端llms/openai/openaillm.go 处的StreamingFunc: opts.StreamingFuncOpenAI 客户端在 llms/openai/internal/openaiclient/chat.go 检测到payload.StreamingFunc ! nil时切换到流式请求模式并在 chat.go 对每个到达的 SSE 数据块执行payload.StreamingFunc(ctx, chunk)最终每个 chunk 回到示例的回调函数中被实时打印。因此启用流式输出无需改动业务代码结构只需通过 CallOption 注入回调——这是 langchaingo 设计上的一致性体现同一套GenerateContent接口同步与流式仅是选项差异。流式与函数调用同时生效值得注意WithStreamingFunc与WithTools可以同时传入同一个GenerateContent调用。在流式模式下函数调用的参数通常也是通过流式块逐步返回的WithStreamingFunc回调中的chunk内容是原始文本块如需在流式过程中解析函数调用参数可以在回调内自行累积拼接 JSON。而示例选择了更简洁的路径流式只用于观察生成过程函数调用结果则等请求完成后统一读取。工具声明WithTools 与函数定义工具集合示例通过llms.WithTools(tools)注册三个工具tools是[]llms.Tool切片llms/options.go 中WithTools的签名即为func WithTools(tools []Tool) CallOption。其中Tool结构定义于 llms/options.go// Tool is a tool that can be used by the model. type Tool struct { // Type is the type of the tool. Type string json:type // Function is the function to call. Function *FunctionDefinition json:function,omitempty }Type固定为functionFunction则指向具体的函数定义。FunctionDefinitionllms/options.go包含四个字段type FunctionDefinition struct { Name string json:name // 函数名如 getCurrentWeather Description string json:description // 对模型描述该函数何时被调用 Parameters any json:parameters,omitempty // JSON Schema 参数定义 Strict bool json:strict,omitempty // 严格模式结构化输出保证需提供商支持 }三个示例函数getCurrentWeather获取指定地点的当前天气。{ Type: function, Function: llms.FunctionDefinition{ Name: getCurrentWeather, Description: Get the current weather in a given location, Parameters: jsonschema.Definition{ Type: jsonschema.Object, Properties: map[string]jsonschema.Definition{ rationale: { Type: jsonschema.String, Description: The rationale for choosing this function call with these parameters, }, location: { Type: jsonschema.String, Description: The city and state, e.g. San Francisco, CA, }, unit: { Type: jsonschema.String, Enum: []string{celsius, fahrenheit}, }, }, Required: []string{rationale, location}, }, }, },getTomorrowWeather获取指定地点的明日预报参数结构与getCurrentWeather一致rationale、location、unit。getSuggestedPrompts根据用户输入生成相关建议提示词参数中包含数组类型suggestionssuggestions: { Type: jsonschema.Array, Items: jsonschema.Definition{ Type: jsonschema.String, Description: A suggested prompt, }, },三个函数共同展示了 langchaingo 参数定义的几个要点参数使用JSON Schema风格声明类型常量jsonschema.Object、jsonschema.String、jsonschema.Array来自仓库的 jsonschema 包每个参数可附带Description用于指导模型正确填充参数值可通过Enum限定取值范围如温度单位仅允许celsius或fahrenheit可通过Required指定必填字段数组类型用Items描述元素结构。示例代码中还保留了一段被注释掉的原始 JSON Schema 写法json.RawMessage(...)说明参数声明支持从任意 JSON Schema 形态转换为jsonschema.Definition结构体两种方式均可工作。本地函数实现虽然模型只会声明要调用哪个函数但真正执行逻辑仍由本地代码完成。示例的getCurrentWeather是模拟实现返回 JSON 格式的天气数据func getCurrentWeather(location string, unit string) (string, error) { weatherInfo : map[string]interface{}{ location: location, temperature: 72, unit: unit, forecast: []string{sunny, windy}, } b, err : json.Marshal(weatherInfo) if err ! nil { return , err } return string(b), nil }函数调用检测读取 FuncCall请求完成后示例通过以下代码检测模型是否发起了函数调用choice1 : resp.Choices[0] if choice1.FuncCall ! nil { fmt.Printf(Function call: %v\n, choice1.FuncCall) }resp是*llms.ContentResponsellms/generatecontent.go其Choices是[]*ContentChoice切片。ContentChoicellms/generatecontent.go包含以下关键字段type ContentChoice struct { Content string // 模型的文本回复 StopReason string // 停止生成的原因 GenerationInfo map[string]any // 模型附加的任意信息 FuncCall *FunctionCall // 非 nil 表示模型请求调用某个函数/工具 ToolCalls []ToolCall // 模型请求调用的工具调用列表 ReasoningContent string // 推理模型的思考内容如 deepseek-reasoner }而FunctionCallllms/generatecontent.go只包含两个字段——函数名与参数 JSON 字符串type FunctionCall struct { Name string json:name // 要调用的函数名 Arguments string json:arguments // 参数JSON 字符串 }由于示例只传入一个用户问题且未提供多轮对话正常情况下模型会生成一个 Choice取出Choices[0]后判断FuncCall是否为 nil 即可知道模型是否决定调用函数。若模型返回的是ToolCalls多工具调用场景可遍历该切片逐个解析每个ToolCall携带ID、Type通常为function以及内嵌的FunctionCallllms/generatecontent.go。说明ContentChoice的注释明确指出当模型一次发起多个工具调用时FuncCall字段只包含第一个完整列表应通过ToolCalls获取见 llms/generatecontent.go。完整调用链小结将上述内容串联示例的完整执行路径为openai.New(WithModel(gpt-4-turbo)) // ① 初始化模型 │ llm.GenerateContent(ctx, messages, // ② 发起请求 WithStreamingFunc(print chunk), // 注入流式回调 WithTools(tools)) // 注入工具声明 │ ├── 流式路径opts.StreamingFunc → OpenAI 客户端 │ 逐个 chunk 回调 → fmt.Printf 实时打印 │ └── 返回路径*llms.ContentResponse ├── resp.Choices[0].Content → 文本回复 └── resp.Choices[0].FuncCall → 非 nil 则打印函数调用常见问题与延伸为什么流式回调打印的 chunk 不是完整句子这是流式SSE的本质——模型按 token 逐步返回内容回调每收到一块就触发一次。这正是示例所强调的实时观察 AI 生成过程见 README。如何真正执行模型请求的函数检测到FuncCall后需要自己写一个switch fn.Name分发到本地实现如示例中的getCurrentWeather再将执行结果以ToolCallResponse形式作为下一轮消息回传给模型。langchaingo 的 agents 包agents提供了更完整的 Agent 循环封装agents目录下的 openai_functions_agent.go 即展示了自动化的工具执行流程。函数调用相关选项除了WithToolslangchaingo 还提供WithToolChoice强制/指定使用某个工具见 llms/options.go与已废弃的WithFunctions建议改用WithTools见 llms/options.go。多工具同时调用当模型返回ToolCalls列表时应遍历处理而非只读FuncCall这两个字段的差异详见前文ContentChoice结构说明。结语这个示例虽然代码量不大却浓缩了 langchaingo 与 OpenAI 交互中最实用的两个能力函数调用让 LLM 具备与外部系统协作的能力流式响应让生成过程对用户实时可见。通过WithTools声明 JSON Schema 化的函数签名、用WithStreamingFunc挂载逐块回调、最后从ContentResponse中解析FuncCall即可在一套简洁的 API 之上组合出具备实时反馈和工具协作能力的 Go LLM 应用。以此为起点可进一步研究仓库中的 agents 模块与 openai_functions_agent_test.go 中的完整 Agent 循环实现将检测函数调用升级为自动执行并继续对话的闭环。【免费下载链接】langchaingoLangChain for Go, the easiest way to write LLM-based programs in Go项目地址: https://gitcode.com/GitHub_Trending/la/langchaingo创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表