惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

V
Visual Studio Blog
T
The Exploit Database - CXSecurity.com
The GitHub Blog
The GitHub Blog
量子位
S
SegmentFault 最新的问题
小众软件
小众软件
酷 壳 – CoolShell
酷 壳 – CoolShell
P
Proofpoint News Feed
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
T
Threat Research - Cisco Blogs
I
Intezer
Hugging Face - Blog
Hugging Face - Blog
Spread Privacy
Spread Privacy
Microsoft Security Blog
Microsoft Security Blog
P
Proofpoint News Feed
Know Your Adversary
Know Your Adversary
人人都是产品经理
人人都是产品经理
G
Google Developers Blog
Cyberwarzone
Cyberwarzone
L
LINUX DO - 热门话题
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
H
Hackread – Cybersecurity News, Data Breaches, AI and More
J
Java Code Geeks
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
T
Tenable Blog
Jina AI
Jina AI
A
About on SuperTechFans
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
MyScale Blog
MyScale Blog
AWS News Blog
AWS News Blog
宝玉的分享
宝玉的分享
WordPress大学
WordPress大学
T
Threatpost
大猫的无限游戏
大猫的无限游戏
I
InfoQ
T
Tor Project blog
Project Zero
Project Zero
F
Full Disclosure
L
Lohrmann on Cybersecurity
P
Palo Alto Networks Blog
G
GRAHAM CLULEY
B
Blog
Apple Machine Learning Research
Apple Machine Learning Research
The Hacker News
The Hacker News
S
Securelist
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
V
V2EX
The Cloudflare Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
面向移动端的企业级 AI Agent 架构设计:从 100 个 API 到按需注入
g-wellsa · 2026-05-15 · via DEV Community

引言
当前公开的技术资料中,移动端原生运行 AI Agent 的完整架构文档相对较少。多数方案(如 LangChain、AutoGen、CrewAI)面向云端服务器设计,假设无限内存、稳定网络、无中断执行。然而,企业内网移动端场景存在独特的约束:API 不能暴露公网、用户可能随时中断对话、横竖屏切换会销毁 Activity、内存有限。本文记录一种在 Android 手机上运行企业级 AI Agent 的架构设计方法,以及实现中常见的 7 类问题与解决方案。文中方案已在实际项目中验证,供移动端 LLM 落地参考。

一、为什么需要移动端原生 Agent?
企业级 AI Agent 通常部署在服务器上,因为算力、网络、内存更充裕。但移动端拥有服务器无法替代的优势:离用户最近,可直接访问设备硬件与企业内网。

典型场景:
企业内部有 40-100 个 REST API(日程、通讯录、审批、汇报……)
员工通过自然语言操作这些系统
企业 API 不能暴露到公网
需要原生移动端体验(非 Web 套壳)
这些约束要求 Agent 引擎在 Android 设备上本地运行。

二、整体架构(七层解耦)
┌─────────────────────────────────────────────┐
│ AgentActivity.kt (UI 层) │
│ 聊天界面 + 授权弹窗 + 中断/切换按钮 │
└──────────────┬──────────────────────────────┘
↓ Flow 双向
┌─────────────────────────────────────────────┐
│ AgentViewModel.kt (中枢层) │
│ StateFlow/SharedFlow 桥接 │
│ 意图路由 + 配置加载 + Skill 注册 │
└──────────────┬──────────────────────────────┘

┌─────────────────────────────────────────────┐
│ AgentModels.kt (数据层) │
│ MemoryNode / EngineEvent / AgentContext │
│ BusinessModule / IntentRouter │
│ + 安全上下文截断器 │
└──────────────┬──────────────────────────────┘

┌─────────────────────────────────────────────┐
│ ConfigProvider.kt (配置层) │
│ LocalAsset / RemoteUrl 双策略 │
└──────────────┬──────────────────────────────┘

┌─────────────────────────────────────────────┐
│ McpFactories.kt (工厂层) │
│ RestApiDoc → McpProxySkill (带护栏) │
│ 真实 HTTP 请求 + 响应格式化 │
└──────────────┬──────────────────────────────┘

┌─────────────────────────────────────────────┐
│ LlmAdapters.kt (大脑层) │
│ OpenAiSseAdapter (Qwen/DeepSeek) │
│ ClaudeSseAdapter (Claude 原生) │
│ SSE 流式 + Tool Calling │
└──────────────┬──────────────────────────────┘

┌─────────────────────────────────────────────┐
│ CoreEngine.kt (引擎层) │
│ DaemonEngine + ReAct 循环(8步) │
│ 工具并行执行 + 人工授权 │
└─────────────────────────────────────────────┘

三、核心模块设计
3.1 具有中断能力的守护引擎(DaemonEngine)
引擎支持硬件级中断:用户可随时终止 Agent 的思考线程。这在移动端极其重要——避免模型无限烧 token。

class DaemonEngine(
    private val hook: AgentHook,
    private val scope: CoroutineScope,
    private var llmApiStrategy: LlmAdapterStrategy
) {
    private val skillRegistry = mutableMapOf<String, Skill>()

    fun dispatch(event: EngineEvent, activeSkillNames: Set<String>? = null) {
        if (event is EngineEvent.HardwareInterrupt) {
            currentExecutionJob?.cancel()
            hook.onFinalize("🛑 [拦截] 已强行终止思考。")
            return
        }
        // 进入 LLM 推理 → ReAct 循环
    }
}

Enter fullscreen mode Exit fullscreen mode

3.2 ReAct 循环
Agent 采用“思考-行动-观察”循环。最多 8 步,防止逻辑死循环。
示例流程:
用户:"删除明天的会议"

模型决定调查询接口 → 查到 3 个会议

模型展示结果 → "明天有3个会议:10:00A、15:00B、17:00C,您要删哪个?"

用户:"下午3点那个"

模型匹配到 B 会议 → 调删除接口

接口返回成功 → 模型生成最终回复

3.3 可热切换的 LLM 适配器
通过策略模式统一不同模型(Qwen、DeepSeek、Claude)的接口,支持运行时热切换。

3.4 技能工厂(McpProxySkill)
无需为每个 API 手写 Skill。通过 JSON 配置文件定义接口蓝图,工厂自动生成可执行技能。

uspend fun buildSkills(): List<Skill> = withContext(Dispatchers.Default) {
    apiDocs.map { doc ->
        McpProxySkill(
            name = "${namespace}/${doc.apiId}",
            description = doc.description,
            parametersJsonSchema = gson.fromJson(doc.paramSchemaJson),
            executeAction = { args, ctx -> /* 真实 HTTP 请求 */ }
        )
    }
}

Enter fullscreen mode Exit fullscreen mode

3.5 语义感知的上下文截断器
移动端内存有限,不能无限保留对话历史。简单的“取最后 N 条”可能切断用户提问→工具调用→工具结果这一完整链条。该方案通过回溯算法保证不破坏工具调用链的语义完整性。

fun getRecentMemoryWindow(maxSize: Int = 20): MutableList<MemoryNode> {
    var safeStartIndex = totalSize - maxSize
    while (safeStartIndex > 0) {
        val node = memoryNodes[safeStartIndex]
        if (node.role == "tool_results") { safeStartIndex--; continue }
        if (node.role == "assistant" && node.toolCallsJson != null) { safeStartIndex--; continue }
        break
    }
    return memoryNodes.subList(safeStartIndex, totalSize)
}

Enter fullscreen mode Exit fullscreen mode

四、实现中常见的 7 类陷阱与解决方案
以下陷阱均来自实际项目中的真实问题,以通用形式列出。

陷阱 1:工具调用响应类型误判
现象:编译时报错或运行时类型不匹配。

原因:将字符串类型的字段直接作为布尔条件判断。

解决方案:使用明确的类型检查,例如 if (response.replyText.isNotEmpty())。

陷阱 2:System Prompt 条件逻辑错误
现象:模型缺少角色定义,行为随机。

原因:添加 system prompt 的条件写反(有 prompt 时不加,没有时加空内容)。

解决方案:正确判断 !sysPrompt.isNullOrEmpty() 后再添加。

陷阱 3:安全护栏条件反置
现象:未查询就允许删除,查过后反而拦截。

原因:前置依赖检查逻辑写反。

解决方案:检查“未执行前置接口”时才拦截,而非“已执行”。

陷阱 4:核心 HTTP 请求被注释
现象:所有 API 调用返回失败。

原因:调试期间注释了真实请求代码,上线前未恢复。

解决方案:使用 feature flag 或 mock 开关,避免注释核心逻辑。

陷阱 5:提示词中的占位符未格式化
现象:LLM 收到的 prompt 中包含字面量 %s。

原因:构建 prompt 时忘记调用 String.format()。

解决方案:使用模板引擎或明确调用格式化方法。

陷阱 6:多套工具调用协议冲突
现象:模型既输出 Markdown JSON 代码块,又输出原生 tool_calls,解析混乱。

原因:提示词中描述的格式与实际代码使用的协议不一致。

解决方案:保持提示词与实际解析逻辑完全一致,只使用一种协议。

陷阱 7:SharedFlow 信号因配置丢失
现象:横竖屏切换后授权弹窗不再出现,引擎卡死。

原因:MutableSharedFlow 的 replay 参数为 0,重建后旧信号丢失。

解决方案:设置 replay = 1 以保留最近一个信号。

五、从 100 个 API 中按需注入:意图路由 + 模块依赖
LLM 的上下文窗口越来越大(Qwen 32K,Claude 200K)。但注意力机制不是“读得下就行”。同时给模型 100 个接口描述,其注意力会被严重稀释。实际测试表明,按需注入 3-8 个接口比全量注入准确率提升 30% 以上,成本降低 85%。

5.1 三种方案对比

方案                     做法               优点  缺点
全量注入               100 个接口全塞     实现零成本  注意力稀释、烧钱
关键词匹配        contains 匹配     零成本    多意图处理不了
意图路由+模块注入    匹配模块→展开依赖精准、  低成本    需维护模块关系

Enter fullscreen mode Exit fullscreen mode

推荐采用意图路由 + 业务模块注入。

5.2 业务模块定义与依赖展开

data class BusinessModule(
    val id: String,              // "calendar"
    val keywords: List<String>,  // 触发关键词
    val apiIds: List<String>,    // 该模块包含的所有接口
    val dependsOn: List<String>, // 依赖的其他模块(自动带出)
    val systemPrompt: String
)

Enter fullscreen mode Exit fullscreen mode

模块依赖示例:

核心路由代码(零三方库):

class IntentRouter(private val modules: List<BusinessModule>) {
    fun resolve(userInput: String): ResolvedContext {
        val lower = userInput.lowercase()
        val matched = modules.filter { it.keywords.any { kw -> lower.contains(kw.lowercase()) } }.toMutableSet()
        val resolved = mutableSetOf<BusinessModule>()
        matched.forEach { resolveDependencies(it, resolved) }
        return ResolvedContext(resolved, resolved.flatMap { it.apiIds }.distinct())
    }

    private fun resolveDependencies(module: BusinessModule, resolved: MutableSet<BusinessModule>) {
        if (module in resolved) return
        module.dependsOn.forEach { depId ->
            modules.find { it.id == depId }?.let { resolveDependencies(it, resolved) }
        }
        resolved.add(module)
    }
}

Enter fullscreen mode Exit fullscreen mode

5.3 模块热切换策略
用户切换话题时,模块不能全量替换,需支持追加与保留:

用户输入 操作
“下午3点那个” 没命中新模块 → 保留当前模块
“对了,帮我查下天气” “对了” → 追加新模块,不清空旧的
“算了,帮我改日程” 命中日程 → 有重叠 → 替换无关模块

5.4 系统提示词分层设计(API 缓存优化)
参考 Hermes Agent 的做法,将 prompt 分为三层:

层内容 变化频率 缓存效果
稳定前缀 角色定义 + 执行规则 启动后不变 ✅ API 缓存命中
动态模块 当前业务模块规则 + 接口列表 切换话题时变 ⚠️ 部分失效
对话历史 最近的 memoryNodes 每轮变化 ❌ 不可缓存
实际测试中,80% 的 prompt 内容稳定,可命中 API 缓存,token 费用降低约 85%。

5.5 效果对比
场景 全量注入 意图路由
每次注入接口数 100 个 3-8 个
Input token 消耗 ~5000 ~800
单次费用 ¥0.02 ¥0.003
月度费用(日均 100 次) ¥60 ¥9
意图识别准确率 72% 94%

六、完整交互时序图

七、相关讨论与局限
7.1 关键词匹配的局限性
本文方案采用简单的 contains() 关键词匹配,未使用分词库或 LLM 分类。原因如下:
避免在移动端引入额外体积(如 Jieba 分词库约 30MB)和初始化延迟。
实际测试中,关键词匹配对 200 条企业真实 query 的命中率为 94%。漏配的多为口语缺关键词(如“帮我把那个事儿弄一下”),此时会 fallback 到当前模块不切换,用户再给一个词即可命中。
适用边界: 适用于关键词意图明确的企业垂直场景。对于开放域闲聊或多轮复杂隐含意图,建议混合轻量级分类模型。

7.2 并行工具执行的条件
方案支持并行调用多个无依赖关系的工具(如同时查天气和日程)。但需注意:
有依赖关系的工具(如先查后删)仍需串行。
并行数不宜过多,避免手机带宽或后端压力过大。

7.3 与其他移动端 Agent 方案的对比
方案 优点 缺点
本文方案 零依赖、低成本、可中断、原生 Kotlin 需要预先定义模块依赖关系
LangChain 移植 生态丰富 体积大、移动端适配差
Direct Function Calling(无路由) 实现简单 100 API 时注意力稀释严重

八、总结
在 Android 手机上运行企业级 AI Agent 并非追求新算法,而是工程细节的胜利。本文提出的架构包含以下关键点:

守护引擎:支持硬件中断,避免无限推理。
语义感知上下文截断:不破坏工具调用链。
意图路由 + 模块依赖展开:从 100 个 API 中精准注入 3-8 个接口,成本降低 85%,准确率提升至 94%。
分层提示词:稳定层命中 API 缓存,进一步节省费用。
技能工厂:通过配置而非编码生成 API 调用能力。

该方案已在企业内部实测,不依赖任何第三方 LLM 编排框架,纯 Kotlin 实现。核心原则: 定义业务模块 + 依赖关系 → 用户输入通过关键词匹配路由 → 递归展开依赖 → 只注入相关接口和规则。不加分词库,不加 LLM 分类,不加重型框架。

九、参考资料与配套代码
配套可运行最小示例(展示意图路由、ReAct 循环、并行工具调用、安全截断):
https://github.com/g-wellsa/DroidAgent.git (请替换为实际 Gist 链接)
相关概念:ReAct 模式、Function Calling、Agent Memory、Android Agent、Api 按需加载