大内密探零零发之 iOS 密探神器 AI 大模型 MCP 服务开发记(下)

引子

上回说到,零零发的 "密探发明聊天棚" 虽已初具雏形,却卡在了最关键的一步 ------ 工具调用结果没法传给军师。

在本篇京城八卦中,您将学到如下内容:

  • 引子
  • 🔄 第五回:打通任督二脉!工具结果传给军师
  • 🧪 第六回:实战演练!看看神器好不好使
    • 第一步:密探发问
    • 第二步:军师接招
    • 第三步:调用工具
    • 第四步:结果回传
    • 第五步:军师总结
  • 🚀 第七回:查漏补缺!这些坑可别踩
  • 🎭 终章:神器大成,零零发的 "发明哲学"

就像他那 "要你命三千" 明明装好了十八般兵器,却忘了装发射按钮,急得零零发抓耳挠腮:"岂有此理!这就好比跟无相皇打架,都掏出刀了却发现没开刃,岂不是贻笑大方?:("


🔄 第五回:打通任督二脉!工具结果传给军师

零零发蹲在地上画了三个圈:"第一步,军师让调用工具;第二步,咱们调用工具拿结果;第三步,把结果塞回给军师。这三步环环相扣,少一步都成不了事!" 说着就在sendMessage里补全了逻辑,活像给断了的经脉接上线。

看看这补全的代码,每一步都透着零零发的 "发明智慧":

swift 复制代码
// 完善后的发送消息方法(新增处理工具调用的逻辑)
func sendMessage() {
    // 上集已有代码:添加用户消息、清空输入框、开始加载
    let userMessage = Request.Message(role: .user, content: [.text(text: inputText)])
    messages.append(ChatMessage(message: userMessage))
    inputText = ""
    isLoading = true
    let allMessages = messages.map(\.message)
    
    Task {
        do {
            let advisorResponse = try await advisorService.send(messages: allMessages)
            let assistantMessage = ChatMessage(
                message: Request.Message(role: .assistant, content: advisorResponse.content)
            )
            self.messages.append(assistantMessage)
            
            // 新增:遍历军师的回复,看看有没有让调用工具
            for content in advisorResponse.content {
                switch content {
                case .toolUse(let toolId, let toolName, let input):
                    // 调用工具,并把结果回传给军师(这步是关键!)
                    try await useTool(toolId: toolId, toolName: toolName, input: input)
                case .text, .toolResult:
                    continue // 其他类型的消息不用处理
                }
            }
        } catch {
            print("出错啦!零零发:'哎呀,零件掉了!' 错误:\(error)")
        }
        isLoading = false
    }
}

// 新增:调用工具并回传结果给军师的方法
private func useTool(toolId: String, toolName: String, input: [String: String]) async throws {
    // 1. 找对应的工具(总不能张冠李戴,拿查发明的工具去测暗器吧)
    guard let tool = inventionServer.tools.first(where: { $0.name == toolName }) else {
        print("没找到工具:\(toolName),零零发:'这零件我好像没见过啊?'")
        return
    }
    
    // 2. 调用工具拿结果(相当于按动"要你命三千"的发射按钮)
    let toolResult = try await inventionServer.call(tool)
    print("工具返回结果:\(toolResult),零零发:'成了!'")
    
    // 3. 把结果包装成"工具结果消息",加到聊天记录里
    let toolResultMessage = Request.Message(
        role: .user, // 注意:工具结果也得算用户这边的消息,不然军师不认
        content: [.toolResult(toolUseId: toolId, content: toolResult)]
    )
    self.messages.append(ChatMessage(message: toolResultMessage))
    
    // 4. 把包含工具结果的所有消息再发给军师,让他接着分析
    let allMessages = self.messages.map(\.message)
    let finalResponse = try await advisorService.send(messages: allMessages)
    let finalMessage = ChatMessage(
        message: Request.Message(role: .assistant, content: finalResponse.content)
    )
    self.messages.append(finalMessage)
}

零零发拍着胸脯说:"瞧见没?这useTool方法就是打通任督二脉的关键!工具结果必须带toolUseId,跟军师发的 ID 对上,不然他老人家哪知道这结果是哪个请求的?就像给皇上递奏折,得标上编号,不然皇上哪记得你上次说的是啥!"

🧪 第六回:实战演练!看看神器好不好使

代码写完了,零零发搓着手说:"是骡子是马拉出来遛遛!咱们模拟个场景 ------ 我问军师'我的天外飞仙破解器状态如何?',看看它能不能自动查、自动答。"

第一步:密探发问

输入框敲上:"军师,我那天外飞仙破解器咋样了?能对付无相皇不?" 点发送。此时 APP 把消息发给 Claude,附带可用工具列表。

第二步:军师接招

Claude 收到消息,一看是查发明状态,立马回复:"稍等,我这就调用工具查查您的天外飞仙破解器状态。" 同时偷偷发了个工具调用指令(藏在 JSON 里,用户看不见):

json 复制代码
{
  "content": [
    {
      "type": "text",
      "text": "我这就帮您查查天外飞仙破解器的状态..."
    },
    {
      "type": "tool_use",
      "id": "toolu_007", // 工具调用ID,等会儿结果要用
      "name": "check_latest_invention",
      "input": {}
    }
  ]
}

第三步:调用工具

APP 检测到tool_use指令,立马调用check_latest_invention工具,从 "密探发明库" 拿到结果:"天外飞仙破解器:电量80%,状态:已校准"

第四步:结果回传

APP 把结果包装成tool_result消息,发给军师:

json 复制代码
{
  "content": [
    {
      "type": "tool_result",
      "tool_use_id": "toolu_007", // 必须跟之前的ID对上
      "content": "天外飞仙破解器:电量80%,状态:已校准"
    }
  ],
  "role": "user"
}

第五步:军师总结

Claude 收到结果,整理成人话回复:"回禀密探,您的天外飞仙破解器目前电量 80%,已校准完毕,对付无相皇绰绰有余!不过记得打完架充个电,免得下次急用。"

零零发看着完整的聊天记录,笑得合不拢嘴:"完美!这流程比我给琴操姑娘修胭脂盒还顺!从发问、调用工具到拿到答案,一气呵成,简直是'居家旅行、杀人灭口'之必备神器啊!"

🚀 第七回:查漏补缺!这些坑可别踩

零零发毕竟是老江湖,知道新发明总有小毛病,特意列了几个 "避坑指南":

  1. 权限问题

    "调用'密探发明库'得先申请权限,不然就像没带腰牌想进皇宫 ------ 门儿都没有!" 务必在 Info.plist 里加好描述,不然 APP 会闪退。

  2. 角色别搞反

    "用户发的消息角色是user,军师是assistant,工具结果也算user这边的。搞错了角色,军师就会像被点了穴 ------ 一动不动,还报错给你看!"

  3. tool_use_id 要对应

    "工具结果的 ID 必须跟军师发的对上,就像暗器上的标记,错了就会乱开枪!" 要是 ID 对不上,Claude 会一脸懵:"这结果是啥玩意儿?我没问过啊!"

  4. 异常处理不能少

    "万一工具调用失败,比如没数据,得告诉用户'查不到哦',别让 APP 直接崩溃。就像我那发明偶尔卡壳,总得有个'重启按钮'吧?"

🎭 终章:神器大成,零零发的 "发明哲学"

零零发把 "密探神器" 往桌上一放,对着镜头感慨道:"你看这 MCP 协议,不就是给 APP 装了个'会思考的脑子'吗?以前的 APP 是'你问一句,它答一句',现在倒好,它会自己找工具、查数据,跟个小密探似的!"

他拿起 "天外飞仙破解器" 比划着:"这就像我当年发明武器,不光要能打,还得会'思考'------ 敌人来了,它自动选刀还是选枪。做 APP 也一样,光有界面不够,得让它懂用户、会办事,这才是'智能'的真谛啊!"

最后,零零发凑近屏幕,挤眉弄眼道:"记住了啊,搞开发就像追姑娘 ------ 得懂她心思,还得有手段。MCP 就是你的'泡妞秘籍',用好了,你的 APP 能跟用户聊得眉来眼去,比我跟琴操姑娘还投缘呢!"

要知零零发与琴操姑娘后事如何?我们下次再叙喽。

感谢宝子们的观赏,再会啦!8-)

相关推荐
一条咸鱼_SaltyFish25 分钟前
[Day14] 微服务开发中 `contract - common` 共享库的问题排查与解决
程序人生·微服务·架构·开源软件·ddd·个人开发·ai编程
冬奇Lab3 小时前
【Cursor进阶实战·07】OpenSpec实战:告别“凭感觉“,用规格驱动AI编程
人工智能·ai编程
IamZJT_4 小时前
拒绝做 AI 的“饲养员” ❌:前端程序员在 AI 时代的生存与进化指南 🚀
前端·ai编程
CoderJia程序员甲5 小时前
GitHub 热榜项目 - 日榜(2026-1-9)
开源·大模型·llm·github·ai教程
极小狐5 小时前
智谱上市!当 GLM-4.7 遇上 CodeRider :演示何为「1+1>2」的巅峰效能
人工智能·ai编程
peterfei6 小时前
AI 把代码改崩溃了?若爱 (IfAI) v0.2.7 发布:程序员的“后悔药”真的来了!
rust·ai编程
树獭非懒6 小时前
AI大模型小白手册|如何像工程师一样写Prompt?
llm·aigc·ai编程
艺杯羹8 小时前
Trae 智能编程工具入门指南:安装流程 + 贪吃蛇实操
ai·ai编程·编程工具·trae·ai开发工具
视觉&物联智能8 小时前
【杂谈】-多智能体系统的效能悖论:协作优势的认知边界
ai·llm·agent·智能体·人工 智能
一条咸鱼_SaltyFish9 小时前
[Day13] 微服务架构下的共享基础库设计:contract-common 模块实践
开发语言·人工智能·微服务·云原生·架构·ai编程