通过OpenAI对接LLM——搭建Geek头条
本次我们会尝试通过OpenAI对接大模型,基于现有工具搭建了Gekk头条,可以每天帮我获取最新科技资讯并做总结。
AI Agent 与 LLM 关系
LLM 扮演了 Agent 的 “大脑”,在 Agent 这个系统中提供推理、规划等能力。——《LLM、Prompt、AI Agent、RAG… 一网打尽大模型热门概念》
一般架构
AI Agent 中 LLM 是最核心的部分,实际工程应用中,还需要建设好周边工具,提供「作业」、「记忆」等能力,结合 LLM 一套建设完整的智能体。
MCP 中 Tools、Prompts、Resources的区别
Primitive | Control | Description | Example |
---|---|---|---|
Prompts | User-controlledPrompts 像是提前配置好的,需要指定后执行,不需要每次填写 |
Interactive templates invoked by user choice | Slash commands, menu options /prompts /prompt generate_search_prompt topic=history num_papers=2 |
Resources | Application-controlled应用选择怎么用,如果需要LLM使用还是需要提供Tools | Contextual data attached and managed by the client | File contents, git history |
Tools | Model-controlled | Functions exposed to the LLM to take actions | API POST requests, file writing |
流程
Geek 头条实现
Geek 头条的流程:
- 调用
tech_news
工具,获取最新科技新闻; - 调用
tech_news_prompt
工具生成提示词; - 调用LLM,生成总结。
OpenAI 对接 LLM
OpenAI除了做模型,也提供了标准API,我们可以直接调用API来调用LLM。
模型申请
我申请的是siliconflow的模型,它支持免费使用 Qwen/Qwen2-7B-Instruct 和 deepseek-ai/DeepSeek-R1-Distill-Qwen-7B 等多种模型。
需要用到的包:
go get github.com/openai/openai-go
初始化 OpenAI
aiClient = openai.NewClient(
option.WithBaseURL("https://api.siliconflow.cn/v1"),
option.WithAPIKey("ApiKey"), // defaults to os.LookupEnv("OPENAI_API_KEY")
)
获取新闻
callToolReq := mcp.CallToolRequest{}
callToolReq.Params.Name = "tech_news"
callResp, err := mcpClient.CallTool(ctx, callToolReq)
获取提示词
getPromptReq := mcp.GetPromptRequest{}
getPromptReq.Params.Name = "tech_news_prompt"
getPromptReq.Params.Arguments = map[string]string{
"news": strings.Join(newsLink, ","),
}
https://github.com/ThinkInAIXYZ/deepchat/releases/tag/v0.1.1,https://tonybai.com/2025/05/20/post-quantum-cryptography-in-go/,https://tonybai.com/2025/05/19/shardedvalue-per-cpu-proposal/ [I] 2025/05/21 21:20:35 new_agent.go:67: https://github.com/ThinkInAIXYZ/deepchat/releases/tag/v0.1.1,https://tonybai.com/2025/05/20/post-quantum-cryptography-in-go/,https://tonybai.com/2025/05/19/shardedvalue-per-cpu-proposal/ 分别总结这些网页,使用网页标题,不需要做对比,并为每个标题附带上文档链接。
调用LLM
params := openai.ChatCompletionNewParams{
Messages: []openai.ChatCompletionMessageParamUnion{
openai.UserMessage(promptMsg), // 提示词,UserMessage代表说用户说的话
},
Model: "deepseek-ai/DeepSeek-R1-Distill-Qwen-7B", // 选择的模型
Tools: ts,
Seed: openai.Int(0),
}
chatCompletion, err := aiClient.Chat.Completions.New(ctx, params)
- User(用户):代表与 AI 进行对话的人类。是对话的发起者和推动者,通过提出问题、表达需求或提供指令来引导对话的方向。
- Assistant(助手):代表 AI 本身,是对用户进行回应的角色。根据系统设定和用户输入生成相应的回复,为用户提供信息、回答问题、完成任务或提供建议等。
finish_reason
chatCompletion.Choices[0].FinishReason
字段保存了 LLM 停止&返回客户的的原因。
原因标识 | 含义解释 |
---|---|
stop | 模型到达自然停止点或遇到提供的停止序列 |
length | 达到请求中指定的最大 token 数量 |
content_filter | 内容因内容过滤器标记被省略 |
tool_calls | 模型调用了工具 |
function_call(deprecated) | 模型调用了函数(已弃用 ) |
渲染
因为生成的内容是markdown格式,这里用到了github.com/gomarkdown/markdown
包来将markdown渲染成html,
func MDToHTML(md []byte) []byte {
// create markdown parser with extensions
extensions := parser.CommonExtensions | parser.AutoHeadingIDs | parser.NoEmptyLineBeforeBlock
p := parser.NewWithExtensions(extensions)
doc := p.Parse(md)
// create HTML renderer with extensions
htmlFlags := html.CommonFlags | html.HrefTargetBlank
opts := html.RendererOptions{Flags: htmlFlags}
renderer := html.NewRenderer(opts)
return markdown.Render(doc, renderer)
}
默认html只能按照文本展示,需要用template.HTML用作安全渲染。
```go
res["news"] = template.HTML(string(views))
最后
效果查询:Geek 头条。
- 为什么是用markdown而不是更结构化的比如json呢?尝试了很多提示词,并不能严格按照期望的格式生成json,经常会有自由发挥的字段,总结的内容也很离谱,还不如用简单的提示词效果好。另外猜测模型本身也是基于markdown训练的,所以对json支持并不友好。
- 关于流程,目前我了解到的是也有流程框架LangChainGo,它和MCP之间也有Adaptar来做适配对接,接下来详细学学看。
原文链接:通过OpenAI对接LLM——搭建Geek头条,转载请注明来源!
–EOF–