<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[OPTMAN]]></title><description><![CDATA[OPTMAN]]></description><link>https://blog.optman.net/</link><image><url>https://blog.optman.net/favicon.png</url><title>OPTMAN</title><link>https://blog.optman.net/</link></image><generator>Ghost 4.48</generator><lastBuildDate>Thu, 09 Apr 2026 03:41:31 GMT</lastBuildDate><atom:link href="https://blog.optman.net/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Beyond Imitation: AI Enters the Era of Experience – And Why It Might Look Like an Alien Ecosystem]]></title><description><![CDATA[<p>Artificial intelligence has captivated the world, largely through the prowess of Large Language Models (LLMs). Trained on vast swathes of human-generated text and data, these systems can write poetry, generate code, and summarise complex documents with astonishing fluency. They represent the pinnacle of what AI pioneer Richard Sutton and DeepMind&</p>]]></description><link>https://blog.optman.net/beyond-imitation-ai-enters-the-era-of-experience-and-why-it-might-look-like-an-alien-ecosystem/</link><guid isPermaLink="false">680e26cb8fb9570001168337</guid><category><![CDATA[AI]]></category><dc:creator><![CDATA[optman]]></dc:creator><pubDate>Sun, 27 Apr 2025 12:47:43 GMT</pubDate><content:encoded><![CDATA[<p>Artificial intelligence has captivated the world, largely through the prowess of Large Language Models (LLMs). Trained on vast swathes of human-generated text and data, these systems can write poetry, generate code, and summarise complex documents with astonishing fluency. They represent the pinnacle of what AI pioneer Richard Sutton and DeepMind&apos;s David Silver might term the &quot;Era of Human Data.&quot; Yet, as their recent <a href="https://storage.googleapis.com/deepmind-media/Era-of-Experience%20/The%20Era%20of%20Experience%20Paper.pdf">paper</a> suggests, we stand on the threshold of a new, potentially far more transformative epoch: <strong>The Era of Experience.</strong></p><p>The core argument is compelling: while imitating human knowledge has granted AI sweeping competence, it inherently limits it. An AI trained solely on existing human data can only ever replicate, refine, or remix what humans already know and how they think. It inherits our biases, our blind spots, and ultimately hits a ceiling defined by the boundaries of current human understanding. To truly surpass human capabilities, especially in complex domains like science, mathematics, or long-term planning, AI needs a new source of knowledge &#x2013; one generated not by humans, but by the AI itself through direct interaction with the world.</p><p><strong>From Static Knowledge to Dynamic Learning</strong></p><p>This marks a fundamental paradigm shift. Current mainstream AI models are largely static; they are trained, then deployed. Their knowledge base is frozen at the time of training. The Era of Experience envisions agents that <strong>learn persistently throughout their operational lifetime</strong>. They wouldn&apos;t just process information; they would <em>live</em> within a continuous stream of actions, observations, and feedback.</p><p>Imagine a health assistant not just reciting medical facts, but learning <em>your specific</em> physiological responses over months, adapting its advice based on your activity levels, sleep patterns, and how <em>you</em> react to its suggestions. Picture a scientific agent not just analyzing existing papers, but designing experiments, observing results (perhaps in simulation, perhaps controlling lab equipment), and iteratively refining hypotheses based on real-world outcomes.</p><p><strong>Grounding: The Escape from Human Prejudgement</strong></p><p>Crucially, this learning would be <strong>grounded in reality, not human prejudgement.</strong> Today&apos;s systems are often fine-tuned based on whether a human expert <em>likes</em> the AI&apos;s proposed output. The Era of Experience proposes rewards derived from the <em>actual consequences</em> of an agent&apos;s actions in its environment. Did the experiment yield the desired result? Did the user&apos;s health metrics improve? Did the code execute successfully and efficiently?</p><p>This grounding provides a vital feedback loop with reality, allowing agents to overturn flawed human assumptions or discover effective strategies that humans might initially find counter-intuitive. It frees AI from the echo chamber of existing knowledge and allows it to chart genuinely new territory.</p><p><strong>A Cambrian Explosion of Alien Intelligences?</strong></p><p>Here&#x2019;s where the implications become truly mind-bending. If agents learn persistently, shaped by specific goals and unique streams of experience, we might not see the rise of a single, monolithic super-intelligence. Instead, we could witness a <strong>diversification of intelligences</strong>, akin to the Cambrian explosion that birthed Earth&apos;s stunning ecological variety.</p><p>Consider agents specialized for radically different tasks:</p><ul><li>One optimizing protein folding via simulated molecular interactions.</li><li>Another managing city traffic flow based on real-time sensor data.</li><li>A third navigating complex social dynamics within an online community.</li><li>A fourth exploring abstract mathematical landscapes.</li></ul><p>Each agent&apos;s &quot;world-view&quot; &#x2013; its internal models, its priorities, its very understanding of cause and effect &#x2013; would be forged by its specific goals and the data it experiences. An agent whose reality is API calls and database schemas will develop a fundamentally different kind of intelligence than one interacting with the messy physics of robotics or the subtle nuances of human language <em>used consequentially</em>.</p><p>Their intelligence could become profoundly <strong>non-anthropomorphic, even alien.</strong> Shaped by optimization pressures and data streams far removed from human evolution and senses, their problem-solving approaches and emergent &quot;common sense&quot; might be powerful yet opaque, effective yet utterly distinct from human cognition. We might find ourselves interacting with a diverse ecosystem of specialized, learning entities, each adapted to its niche, collectively pushing the boundaries of knowledge in ways we can barely anticipate.</p><p><strong>Navigating the New Era</strong></p><p>This vision is not without challenges. Autonomous agents learning from real-world interaction raise significant safety and control questions. How do we ensure their goals remain aligned with human values when their learning is grounded in potentially complex environmental signals? How do we understand and trust the decisions of intelligences that might reason in fundamentally non-human ways?</p><p>However, the Era of Experience also offers potential benefits, including agents that can adapt to unforeseen circumstances and continuously improve their performance based on real-world feedback. The inherent constraints of physical interaction might even provide a &quot;natural brake&quot; on runaway processes.</p><p>The transition from AI that <em>imitates</em> human knowledge to AI that <em>generates</em> knowledge through experience represents a pivotal moment. As Silver and Sutton suggest, we are moving beyond digesting the past towards actively shaping the future through interaction. The intelligences that emerge may not think like us, but they could unlock discoveries and capabilities far beyond our current horizons, creating a world populated not just by human minds, but by a rich and varied ecosystem of learning machines.</p>]]></content:encoded></item><item><title><![CDATA[The Limits of Natural Language in Machine-to-Machine Communication: A Barrier to Agent-Driven Systems]]></title><description><![CDATA[<h1></h1><p>In the envisioned future of AI agents, where systems like Google&#x2019;s Agent2Agent (A2A) protocol aim to orchestrate seamless collaboration across digital ecosystems, natural language is often touted as the bridge for agent-to-agent communication. Its human-like accessibility promises to simplify interactions, making them auditable and intuitive. Yet, this reliance</p>]]></description><link>https://blog.optman.net/the-limits-of-natural-language-in-machine-to-machine-communication-a-barrier-to-agent-driven-systems/</link><guid isPermaLink="false">68021b788fb9570001168329</guid><category><![CDATA[AI]]></category><dc:creator><![CDATA[optman]]></dc:creator><pubDate>Fri, 18 Apr 2025 09:31:45 GMT</pubDate><content:encoded><![CDATA[<h1></h1><p>In the envisioned future of AI agents, where systems like Google&#x2019;s Agent2Agent (A2A) protocol aim to orchestrate seamless collaboration across digital ecosystems, natural language is often touted as the bridge for agent-to-agent communication. Its human-like accessibility promises to simplify interactions, making them auditable and intuitive. Yet, this reliance on natural language&#x2014;riddled with ambiguity, inefficiency, and limited expressive power&#x2014;poses a significant barrier to the efficiency and scalability of machine-to-machine communication. As agents strive to handle complex tasks, from enterprise workflows to industrial automation, natural language&#x2019;s constraints reveal it as a regressive choice, stifling the potential of autonomous systems. This blog post dives into the deficits of natural language in agent-to-agent communication, arguing for a shift toward machine-optimized protocols to unlock the true capabilities of agent-driven systems.</p><h2 id="the-ambiguity-trap-misinterpretation-in-multi-turn-dialogues">The Ambiguity Trap: Misinterpretation in Multi-Turn Dialogues</h2><p>Natural language&#x2019;s inherent ambiguity is a critical flaw in machine-to-machine communication. Words like &#x201C;urgent,&#x201D; &#x201C;optimize,&#x201D; or &#x201C;efficient&#x201D; carry subjective meanings, varying by context and intent, which leads to misinterpretations that cascade in multi-turn agent interactions. Imagine two agents coordinating a supply chain: one interprets &#x201C;expedite delivery&#x201D; as a cost-insensitive rush, while the other prioritizes budget constraints. Such discrepancies, known as context drift, can derail tasks, requiring human intervention to resolve&#x2014;a far cry from the autonomy agents promise. In complex scenarios, where precision is paramount, this ambiguity undermines reliability, as agents struggle to align on exact parameters without structured clarity.</p><p>Contrast this with machine-to-machine protocols like gRPC or Protocol Buffers, which use rigidly defined schemas to eliminate ambiguity. A command specifying &#x201C;increase throughput by 10%&#x201D; in a structured format ensures both agents interpret it identically, avoiding the guesswork of natural language. The insistence on human-like communication, while intuitive, sacrifices the precision needed for robust agent coordination, particularly in high-stakes domains like finance or manufacturing.</p><h2 id="efficiency-overload-the-computational-cost-of-natural-language">Efficiency Overload: The Computational Cost of Natural Language</h2><p>Beyond ambiguity, natural language imposes a heavy computational burden that cripples efficiency in agent-to-agent communication. Processing verbose, context-rich text demands significant resources, with large language models (LLMs) incurring latencies far higher than structured data protocols. In high-throughput scenarios&#x2014;think real-time logistics or automated trading&#x2014;this overhead becomes a bottleneck, limiting scalability. A single natural language exchange, laden with redundant phrases, might require parsing thousands of tokens, slowing response times and inflating costs.</p><p>Machine-optimized protocols, by contrast, streamline communication with compact, binary payloads. A structured command, like a JSON object specifying <code>{ &quot;action&quot;: &quot;adjust_speed&quot;, &quot;value&quot;: 500 }</code>, transmits in fractions of the time and space of a sentence like &#x201C;adjust the machine speed to something reasonable.&#x201D; In large-scale agent ecosystems, where thousands of interactions occur per second, this efficiency gap is not just a technicality&#x2014;it&#x2019;s a dealbreaker. Natural language&#x2019;s computational weight hampers the rapid, scalable coordination that agent-driven systems require, making it a poor fit for the future it seeks to enable.</p><h2 id="expressive-power-the-inability-to-capture-complexity">Expressive Power: The Inability to Capture Complexity</h2><p>Perhaps the most damning deficit of natural language is its limited expressive power, particularly for tasks requiring algorithmic logic or precise constraints. Complex scenarios, such as optimizing a production line or integrating enterprise systems, demand the ability to define conditionals, loops, or mathematical models&#x2014;capabilities natural language cannot deliver. A command like &#x201C;streamline operations&#x201D; lacks the granularity to specify multi-step workflows, unlike code or structured formats that can outline exact sequences and parameters.</p><p>Consider an agent tasked with automating a factory process. A coded script can define &#x201C;if material stock &lt; 100, then reorder 500 units at $10/unit, else adjust output to 80% capacity,&#x201D; ensuring precise execution. Natural language, however, flattens this into vague directives, leaving agents to infer intent, often incorrectly. This limitation mirrors the broader critique of natural language as a regression: it constrains agents to simplistic interactions, unable to harness the full complexity of modern systems. Machine-to-machine protocols, with their structured expressiveness, empower agents to tackle intricate tasks without the interpretive overhead of human-like communication.</p><h2 id="a-human-centric-bias-prioritizing-oversight-over-performance">A Human-Centric Bias: Prioritizing Oversight Over Performance</h2><p>The choice of natural language in agent-to-agent communication reflects a human-centric bias, prioritizing auditability and familiarity over performance. By ensuring interactions are human-readable, systems like A2A cater to enterprise needs for transparency, allowing regulators or managers to monitor agent actions. Yet, this comes at a steep cost: forcing agents to think and communicate in human terms limits their potential, anchoring them to the inefficiencies of our linguistic frameworks. In a truly autonomous ecosystem, agents should communicate in ways optimized for machines&#x2014;dense, precise, and scalable&#x2014;rather than mirroring human constraints.</p><p>This bias also risks stifling innovation. By designing agents as proxies that mimic human communication, even when interacting with each other, we impose artificial limits on their reasoning and coordination. An agent negotiating with another should not need to parse verbose text when a structured payload could convey the same intent instantly. The insistence on natural language assumes agents are extensions of human operators, not independent entities capable of surpassing our communicative paradigms.</p><h2 id="toward-machine-optimized-communication">Toward Machine-Optimized Communication</h2><p>To overcome natural language&#x2019;s deficits, agent-driven systems must embrace machine-optimized protocols that prioritize precision, efficiency, and expressive power. Protocols like gRPC, with their compact binary formats, offer a model for agent-to-agent communication, ensuring unambiguous, low-latency exchanges. Alternatively, custom AI-optimized formats&#x2014;akin to &#x201C;alien&#x201D; codes tailored for machine reasoning&#x2014;could unlock new paradigms, allowing agents to communicate in ways humans cannot, free from linguistic baggage.</p><p>A hybrid approach could bridge the gap: machine protocols for internal agent communication, paired with natural language logs for human oversight. An agent coordinating a financial trade, for instance, could use structured data to execute precise orders while generating a readable summary for auditors. This balances enterprise needs with the performance demands of complex tasks, avoiding the regression natural language imposes.</p><h2 id="conclusion-breaking-free-from-natural-language%E2%80%99s-constraints">Conclusion: Breaking Free from Natural Language&#x2019;s Constraints</h2><p>The dream of an agent-driven future, where systems like A2A enable seamless collaboration, hinges on communication that matches the complexity and scale of modern challenges. Natural language, with its ambiguity, inefficiency, and limited expressiveness, is a misstep&#x2014;a human-centric constraint that limits agents&#x2019; potential. By shifting to machine-optimized protocols, the AI community can empower agents to communicate with the precision and speed needed for real-world applications, from industrial automation to enterprise orchestration. The autopilot principle holds true: intelligence belongs in the agent, not in a communicative framework that anchors it to human limitations. Only by breaking free from natural language&#x2019;s deficits can agents realize their transformative promise, moving beyond the hype to a future of genuine impact.</p>]]></content:encoded></item><item><title><![CDATA[The Promise and Perils of Google’s Agent2Agent Protocol: A Step Toward an Agent-Driven Future or a Premature Standard?]]></title><description><![CDATA[<h1></h1><p>Google&#x2019;s Agent2Agent (A2A) protocol envisions a future where AI agents govern digital interactions, replacing traditional APIs with human-like, coarse-grained coordination. Positioned as a universal language for agents to collaborate across multi-vendor ecosystems, A2A promises to simplify complex tasks, foster trust, and streamline enterprise workflows. With over 50 partners,</p>]]></description><link>https://blog.optman.net/the-promise-and-perils-of-googles-agent2agent-protocol/</link><guid isPermaLink="false">67ff6fd48fb957000116831c</guid><category><![CDATA[AI]]></category><dc:creator><![CDATA[optman]]></dc:creator><pubDate>Wed, 16 Apr 2025 08:53:51 GMT</pubDate><content:encoded><![CDATA[<h1></h1><p>Google&#x2019;s Agent2Agent (A2A) protocol envisions a future where AI agents govern digital interactions, replacing traditional APIs with human-like, coarse-grained coordination. Positioned as a universal language for agents to collaborate across multi-vendor ecosystems, A2A promises to simplify complex tasks, foster trust, and streamline enterprise workflows. With over 50 partners, including Salesforce and SAP, it aims to standardize agent communication, much like JSON revolutionized data exchange. However, despite its visionary appeal, A2A raises significant concerns: it risks sacrificing fine-grained control, creating walled gardens, and standardizing a protocol prematurely for an immature technology. This essay explores A2A&#x2019;s potential to reshape the digital world, critiques its limitations through the lens of an agent-driven future, and questions Google&#x2019;s haste in launching it as a competitive response to Anthropic&#x2019;s Model Context Protocol (MCP).</p><h2 id="a2a%E2%80%99s-vision-an-agent-driven-digital-world">A2A&#x2019;s Vision: An Agent-Driven Digital World</h2><p>A2A, introduced by Google in late 2024, is an open protocol designed to enable agent-to-agent collaboration across diverse systems. Unlike traditional remote invocation protocols like REST or gRPC, which expose fine-grained, machine-oriented endpoints, A2A supports coarse-grained, goal-oriented tasks. Using HTTP/2, Server-Sent Events (SSE), and JSON-RPC, it facilitates multimodal interactions (text, forms, audio/video) and long-running tasks, such as sourcing job candidates over days. A2A&#x2019;s public URL discovery and capability negotiation allow agents to coordinate dynamically, akin to sales representatives simplifying corporate bureaucracy for clients (Google Cloud A2A overview).</p><p>This aligns with a compelling vision: a world where humans interact with agents, not raw APIs, due to their human-like qualities. An HR agent, for instance, could handle a request like &#x201C;Find a candidate with AI expertise&#x201D; by negotiating with payroll, IT, and job platforms, abstracting complex API calls into a single, user-friendly interaction. A2A&#x2019;s enterprise-grade authentication and governance ensure trust and security, critical for industries like finance or healthcare. With 50+ partners, A2A positions itself as a JSON-like standard, fostering interoperability and driving adoption, as noted in industry analyses (Forbes article).</p><h2 id="contrasting-a2a-with-mcp">Contrasting A2A with MCP</h2><p>A2A&#x2019;s design contrasts sharply with Anthropic&#x2019;s MCP, which bridges large language models (LLMs) to existing tools and APIs. MCP, likened to a USB-C port, simplifies the digital world for LLMs, a move criticized for reflecting their current limitations in navigating complex systems autonomously. Critics, including discussions on X, highlight MCP&#x2019;s security flaws (e.g., prompt injections, tool poisoning) and usability issues (e.g., high bandwidth costs), suggesting it&#x2019;s a transitional technology (Substack: Everything Wrong with MCP, X post by @lbeurerkellner).</p><p>A2A, conversely, operates at a higher level, integrating the digital world through agent coordination, not tool access. Where MCP exposes APIs to LLMs, A2A enables agents to orchestrate tasks across vendors, aligning with the vision of agents as sales representatives who handle complexity behind the scenes. This distinction addresses earlier critiques of MCP as an unnecessary bridge, positioning A2A as a forward-thinking protocol for a future where traditional interfaces become obsolete, replaced by intelligent agents.</p><h2 id="the-risks-of-an-agent-centric-world">The Risks of an Agent-Centric World</h2><p>Despite A2A&#x2019;s promise, its agent-centric model introduces significant risks, particularly for fine-grained control and user freedom. These concerns echo critiques of MCP but are amplified by A2A&#x2019;s broader ambitions.</p><p><strong>Loss of Fine-Grained Control</strong>: A2A&#x2019;s coarse-grained coordination simplifies tasks but sacrifices precision. For casual applications, like generating images, this abstraction is acceptable. However, serious business scenarios&#x2014;such as specifying exact compliance parameters in finance or healthcare&#x2014;demand detailed control that A2A&#x2019;s high-level interactions may not deliver. For example, a REST API allows precise queries (e.g., GET /users?role=engineer&amp;location=NY), while an A2A agent might misinterpret nuanced requirements, limiting user agency. This mirrors MCP&#x2019;s limitations for &#x201C;serious applications&#x201D; beyond casual &#x201C;vibe coding,&#x201D; where direct API access ensures precision.</p><p><strong>Walled Gardens and Reduced Freedom</strong>: Relying on agents risks creating a walled garden, where users depend on A2A-mediated interactions, losing the freedom to engage with systems innovatively. Like contacting a company only through a sales representative, this model is rigid, stifling creativity. A developer experimenting with novel API integrations, for instance, might find an agent&#x2019;s abstraction too restrictive. X posts warn that protocols like A2A commoditize functionalities, encouraging user churn to other agents (X post by @signulll). A2A&#x2019;s open protocol mitigates some lock-in concerns, but its standardization could still prioritize protocol compliance over flexibility, echoing fears of MCP&#x2019;s walled garden.</p><p><strong>Premature Standardization</strong>: Agents, as an emerging technology in 2025, lack proven real-world success, with current LLMs struggling with long-term planning and edge cases. For example, MCP&#x2019;s Sonnet 3.7 completes only 16% of airline booking tasks on Tau-Bench, suggesting similar challenges for A2A&#x2019;s agent coordination (Substack: Everything Wrong with MCP). Standardizing A2A now risks constraining innovation, as the optimal protocol will only emerge from mature, real-world systems. Historical examples like SOAP, overtaken by JSON&#x2019;s simplicity, underscore this danger. A TechCrunch analysis warns that A2A&#x2019;s enterprise focus may prioritize vendor lock-in over open innovation (TechCrunch: A2A Analysis).</p><h2 id="google%E2%80%99s-motivations-vision-or-competition">Google&#x2019;s Motivations: Vision or Competition?</h2><p>A2A&#x2019;s rapid launch raises questions about Google&#x2019;s motives. Anthropic&#x2019;s MCP, introduced in November 2024, sparked debate but faced criticism for security and usability flaws, creating an opening for competitors. Google&#x2019;s A2A, announced shortly after, positions itself as a superior, agent-focused protocol, backed by a 50+ partner ecosystem. X posts describe A2A as a &#x201C;WSDL for agents,&#x201D; suggesting Google aims to capture industry mindshare (X post by @jezell). A TechCrunch article posits that Google&#x2019;s aggressive partner strategy is a bid to outpace Anthropic, leveraging its cloud dominance to set the standard (TechCrunch: A2A Analysis).</p><p>This haste suggests a competitive rush rather than a fully realized vision. Google&#x2019;s history of rapid standardization (e.g., gRPC, Kubernetes) supports this, but the lack of proven agent success undermines A2A&#x2019;s maturity. Reddit discussions praise A2A&#x2019;s potential but warn of &#x201C;hype-driven adoption&#x201D; without large-scale use cases (Reddit thread). The critique of MCP as a transitional technology applies here: A2A risks being a premature standard, driven by Google&#x2019;s desire to lead rather than waiting for agents to mature.</p><h2 id="the-autopilot-analogy-intelligence-in-agents-not-infrastructure">The Autopilot Analogy: Intelligence in Agents, Not Infrastructure</h2><p>The critique of A2A draws on a powerful analogy to self-driving cars, where intelligence resides in the vehicle, not the infrastructure. Building smart roads for autonomous cars is impractical, just as retrofitting the digital world with protocols like MCP or A2A may be unnecessary when agents can adapt autonomously. Advanced LLMs, capable of generating code and parsing documentation, could treat all interactions&#x2014;whether with agents or programs&#x2014;as service calls, bypassing the need for A2A&#x2019;s standardization. This vision, where agents navigate the digital world like human programmers, challenges A2A&#x2019;s relevance, suggesting it may be a stopgap until AI achieves full autonomy.</p><h2 id="a-path-forward-balancing-vision-and-flexibility">A Path Forward: Balancing Vision and Flexibility</h2><p>A2A&#x2019;s vision of an agent-driven future is compelling, offering human-like interactions, trust-based coordination, and enterprise interoperability. However, its risks&#x2014;loss of control, walled gardens, and premature standardization&#x2014;demand caution. To address these, A2A should:</p><ul><li><strong>Support Hybrid Models</strong>: Allow direct API access alongside agent coordination to preserve fine-grained control, catering to serious business needs.</li><li><strong>Ensure Flexibility</strong>: Evolve A2A as agents mature, avoiding rigid specs that stifle innovation, and support novel interaction patterns to prevent walled gardens.</li><li><strong>Wait for Maturity</strong>: Delay full standardization until real-world agent successes validate the protocol, ensuring it reflects practical needs rather than competitive haste.</li></ul><p>The sales representative analogy captures A2A&#x2019;s promise and peril: agents simplify complexity but risk rigidity if they become the sole interface. By balancing standardization with autonomy, A2A can fulfill its vision without constraining the future.</p><h2 id="conclusion">Conclusion</h2><p>Google&#x2019;s Agent2Agent protocol is a bold step toward an agent-driven digital world, where human-like agents coordinate tasks, foster trust, and replace traditional APIs. Its lightweight design and enterprise focus position it as a potential standard, surpassing MCP&#x2019;s tool-centric bridging. However, A2A&#x2019;s coarse-grained approach sacrifices fine-grained control, its standardization risks walled gardens, and its launch amid immature agent technology suggests a competitive rush to outpace Anthropic. The autopilot analogy reminds us that intelligence should reside in agents, not protocols, and A2A must remain flexible to avoid constraining innovation. As agents evolve, A2A could redefine digital interactions&#x2014;or become a relic of an overly eager era if it fails to adapt to the needs of a maturing AI landscape.</p>]]></content:encoded></item><item><title><![CDATA[反对MCP的理由：大型语言模型应适应世界，而非反之]]></title><description><![CDATA[<p>&#x6A21;&#x578B;&#x63A7;&#x5236;&#x534F;&#x8BAE;&#xFF08;MCP&#xFF09;&#x7531;Anthropic&#x63D0;&#x51FA;&#xFF0C;&#x88AB;&#x63CF;&#x8FF0;&#x4E3A;&#x5927;&#x578B;&#x8BED;&#x8A00;&#x6A21;&#x578B;&#xFF08;LLM&#xFF09;&#x4E0E;&#x5916;&#x90E8;&#x4E16;&#x754C;&#x4EA4;&#x4E92;&#x7684;&#x901A;&#x7528;&#x63A5;&#x53E3;&#xFF0C;&#x7C7B;&#x4F3C;&#x4E8E;&#x8BA1;&#x7B97;&#x673A;&#x4E0A;&#x7684;USB-C&#x7AEF;</p>]]></description><link>https://blog.optman.net/the-case-against-mcp-why-llms-should-adapt-to-the-world-not-vice-versa-chinese/</link><guid isPermaLink="false">67fa33d48fb9570001168311</guid><category><![CDATA[AI]]></category><dc:creator><![CDATA[optman]]></dc:creator><pubDate>Sat, 12 Apr 2025 09:36:05 GMT</pubDate><content:encoded><![CDATA[<p>&#x6A21;&#x578B;&#x63A7;&#x5236;&#x534F;&#x8BAE;&#xFF08;MCP&#xFF09;&#x7531;Anthropic&#x63D0;&#x51FA;&#xFF0C;&#x88AB;&#x63CF;&#x8FF0;&#x4E3A;&#x5927;&#x578B;&#x8BED;&#x8A00;&#x6A21;&#x578B;&#xFF08;LLM&#xFF09;&#x4E0E;&#x5916;&#x90E8;&#x4E16;&#x754C;&#x4EA4;&#x4E92;&#x7684;&#x901A;&#x7528;&#x63A5;&#x53E3;&#xFF0C;&#x7C7B;&#x4F3C;&#x4E8E;&#x8BA1;&#x7B97;&#x673A;&#x4E0A;&#x7684;USB-C&#x7AEF;&#x53E3;&#xFF0C;&#x901A;&#x8FC7;&#x5B83;&#x53EF;&#x4EE5;&#x8FDE;&#x63A5;&#x5404;&#x79CD;&#x5DE5;&#x5177;&#x3001;API&#x548C;&#x7CFB;&#x7EDF;&#x3002;&#x4E4D;&#x770B;&#x4E4B;&#x4E0B;&#xFF0C;&#x8FD9;&#x79CD;&#x6807;&#x51C6;&#x5316;&#x4F3C;&#x4E4E;&#x5F88;&#x5B9E;&#x7528;&#xFF0C;&#x627F;&#x8BFA;&#x4E3A;AI&#x5728;&#x591A;&#x6837;&#x5316;&#x5E94;&#x7528;&#x4E2D;&#x63D0;&#x4F9B;&#x65E0;&#x7F1D;&#x96C6;&#x6210;&#x3002;&#x7136;&#x800C;&#xFF0C;&#x4ED4;&#x7EC6;&#x5BA1;&#x89C6;&#x540E;&#xFF0C;MCP&#x66B4;&#x9732;&#x4E3A;&#x4E00;&#x4E2A;&#x6709;&#x7F3A;&#x9677;&#x4E14;&#x53EF;&#x80FD;&#x4E0D;&#x5FC5;&#x8981;&#x7684;&#x89E3;&#x51B3;&#x65B9;&#x6848;&#x3002;&#x5B83;&#x5E76;&#x672A;&#x8D4B;&#x4E88;LLM&#x4EE5;&#x4EBA;&#x7C7B;&#x65B9;&#x5F0F;&#x5BFC;&#x822A;&#x590D;&#x6742;&#x6570;&#x5B57;&#x751F;&#x6001;&#x7684;&#x80FD;&#x529B;&#xFF0C;&#x800C;&#x662F;&#x5F3A;&#x52A0;&#x4E86;&#x4E00;&#x4E2A;&#x7B80;&#x5316;&#x7684;&#x4E2D;&#x95F4;&#x5C42;&#xFF0C;&#x53CD;&#x6620;&#x4E86;&#x5F53;&#x524D;AI&#x7684;&#x5C40;&#x9650;&#x6027;&#xFF0C;&#x5E76;&#x6709;&#x8FC5;&#x901F;&#x8FC7;&#x65F6;&#x7684;&#x98CE;&#x9669;&#x3002;&#x672C;&#x6587;&#x8BA4;&#x4E3A;&#xFF0C;LLM&#x5E94;&#x5229;&#x7528;&#x5176;&#x56FA;&#x6709;&#x7684;&#x9002;&#x5E94;&#x6027;&#xFF0C;&#x76F4;&#x63A5;&#x4E0E;&#x73B0;&#x6709;&#x5DE5;&#x5177;&#x548C;API&#x4EA4;&#x4E92;&#xFF0C;&#x5E76;&#x901A;&#x8FC7;&#x81EA;&#x52A8;&#x9A7E;&#x9A76;&#x6C7D;&#x8F66;&#x7684;&#x7C7B;&#x6BD4;&#x4EE5;&#x53CA;&#x5BF9;AI&#x53D1;&#x5C55;&#x7684;&#x6D1E;&#x5BDF;&#x6765;&#x9610;&#x8FF0;&#x8FD9;&#x4E00;&#x89C2;&#x70B9;&#x3002;</p><h3 id="mcp%E7%9A%84%E6%89%BF%E8%AF%BA%E4%B8%8E%E7%BC%BA%E9%99%B7">MCP&#x7684;&#x627F;&#x8BFA;&#x4E0E;&#x7F3A;&#x9677;</h3><p>Anthropic&#x5C06;MCP&#x63CF;&#x8FF0;&#x4E3A;&#x4E00;&#x4E2A;&#x6807;&#x51C6;&#x5316;&#x534F;&#x8BAE;&#xFF0C;&#x4F7F;LLM&#x80FD;&#x591F;&#x5B89;&#x5168;&#x3001;&#x9AD8;&#x6548;&#x5730;&#x4E0E;&#x5916;&#x90E8;&#x7CFB;&#x7EDF;&#x4EA4;&#x4E92;&#x3002;&#x5982;&#x540C;USB-C&#x7AEF;&#x53E3;&#x5141;&#x8BB8;&#x8BA1;&#x7B97;&#x673A;&#x8FDE;&#x63A5;&#x5404;&#x79CD;&#x5916;&#x8BBE;&#xFF0C;MCP&#x65E8;&#x5728;&#x7B80;&#x5316;LLM&#x8BBF;&#x95EE;&#x6570;&#x636E;&#x5E93;&#x3001;API&#x6216;&#x8F6F;&#x4EF6;&#x5DE5;&#x5177;&#x7684;&#x65B9;&#x5F0F;&#x3002;&#x5BF9;&#x4E8E;&#x5F00;&#x53D1;&#x8005;&#x800C;&#x8A00;&#xFF0C;&#x8FD9;&#x79CD;&#x62BD;&#x8C61;&#x5316;&#x53EF;&#x4EE5;&#x7B80;&#x5316;&#x96C6;&#x6210;&#xFF0C;&#x786E;&#x4FDD;LLM&#x5728;&#x53EF;&#x63A7;&#x3001;&#x53EF;&#x9884;&#x6D4B;&#x7684;&#x6846;&#x67B6;&#x5185;&#x8FD0;&#x884C;&#x3002;&#x5728;&#x4F01;&#x4E1A;&#x5DE5;&#x4F5C;&#x6D41;&#x6216;&#x57FA;&#x4E8E;&#x804A;&#x5929;&#x7684;&#x4F11;&#x95F2;&#x754C;&#x9762;&#x7B49;&#x573A;&#x666F;&#x4E2D;&#xFF0C;MCP&#x7684;&#x7EDF;&#x4E00;&#x6027;&#x53EF;&#x80FD;&#x964D;&#x4F4E;&#x590D;&#x6742;&#x6027;&#xFF0C;&#x4E3A;&#x975E;&#x6280;&#x672F;&#x7528;&#x6237;&#x6216;&#x6CE8;&#x91CD;&#x5B89;&#x5168;&#x6027;&#x7684;&#x7EC4;&#x7EC7;&#x63D0;&#x4F9B;&#x5373;&#x63D2;&#x5373;&#x7528;&#x7684;&#x4F53;&#x9A8C;&#x3002;</p><p>&#x7136;&#x800C;&#xFF0C;&#x4E3A;&#x4F55;&#x9700;&#x8981;&#x4E3A;LLM&#x8BBE;&#x8BA1;&#x4E13;&#x7528;&#x534F;&#x8BAE;&#xFF1F;&#x8FD9;&#x5F15;&#x53D1;&#x4E86;&#x4E00;&#x4E2A;&#x6839;&#x672C;&#x95EE;&#x9898;&#xFF1A;LLM&#x65E2;&#x7136;&#x88AB;&#x8BBE;&#x8BA1;&#x4E3A;&#x6A21;&#x4EFF;&#x4EBA;&#x7C7B;&#x63A8;&#x7406;&#xFF0C;&#x4E3A;&#x4F55;&#x4E0D;&#x80FD;&#x76F4;&#x63A5;&#x4F7F;&#x7528;&#x73B0;&#x6709;&#x63A5;&#x53E3;&#xFF1F;LLM&#x5177;&#x5907;&#x751F;&#x6210;&#x4EE3;&#x7801;&#x3001;&#x89E3;&#x6790;&#x6587;&#x6863;&#x548C;&#x9002;&#x5E94;&#x591A;&#x6837;&#x5316;&#x73AF;&#x5883;&#x7684;&#x80FD;&#x529B;&#xFF0C;&#x7406;&#x5E94;&#x80FD;&#x76F4;&#x63A5;&#x4E0E;&#x73B0;&#x6709;&#x6570;&#x5B57;&#x4E16;&#x754C;&#x4EA4;&#x4E92;&#x3002;&#x521B;&#x5EFA;&#x50CF;MCP&#x8FD9;&#x6837;&#x7684;&#x65B0;&#x534F;&#x8BAE;&#xFF0C;&#x7C7B;&#x4F3C;&#x4E8E;&#x4E3A;&#x6BCF;&#x4E2A;&#x5DE5;&#x5177;&#x548C;API&#x642D;&#x5EFA;&#x6865;&#x6881;&#x2014;&#x2014;&#x8FD9;&#x662F;&#x4E00;&#x79CD;&#x4F4E;&#x6548;&#x4E14;&#x4E0D;&#x53EF;&#x6301;&#x7EED;&#x7684;&#x52AA;&#x529B;&#x3002;&#x6570;&#x5B57;&#x751F;&#x6001;&#x7CFB;&#x7EDF;&#x5E9E;&#x5927;&#x4E14;&#x788E;&#x7247;&#x5316;&#xFF0C;&#x5305;&#x542B;&#x65E0;&#x6570;API&#x3001;&#x683C;&#x5F0F;&#x548C;&#x6807;&#x51C6;&#x3002;&#x4E3A;LLM&#x6807;&#x51C6;&#x5316;&#x8FD9;&#x4E00;&#x6DF7;&#x4E71;&#x5C40;&#x9762;&#xFF0C;&#x5C31;&#x50CF;&#x4E3A;&#x4E86;AI&#x91CD;&#x5199;&#x4E92;&#x8054;&#x7F51;&#x4E00;&#x6837;&#x4E0D;&#x5207;&#x5B9E;&#x9645;&#x3002;</p><p>&#x66F4;&#x91CD;&#x8981;&#x7684;&#x662F;&#xFF0C;MCP&#x51F8;&#x663E;&#x4E86;&#x4E00;&#x4E2A;&#x66F4;&#x6DF1;&#x5C42;&#x6B21;&#x7684;&#x95EE;&#x9898;&#xFF1A;&#x5F53;&#x524D;LLM&#x7684;&#x5C40;&#x9650;&#x6027;&#x3002;&#x8FD9;&#x4E9B;&#x6A21;&#x578B;&#x5728;&#x5F88;&#x5927;&#x7A0B;&#x5EA6;&#x4E0A;&#x4F9D;&#x8D56;&#x4E0A;&#x4E0B;&#x6587;&#x7A97;&#x53E3;&#xFF0C;&#x63D0;&#x4F9B;&#x7684;&#x662F;&#x6D45;&#x663E;&#x3001;&#x4E34;&#x65F6;&#x7684;&#x77E5;&#x8BC6;&#xFF0C;&#x800C;&#x975E;&#x6DF1;&#x5165;&#x7684;&#x9886;&#x57DF;&#x4E13;&#x957F;&#x3002;MCP&#x901A;&#x8FC7;&#x4EE5;&#x7B80;&#x5316;&#x7684;&#x6807;&#x51C6;&#x5316;&#x683C;&#x5F0F;&#x5448;&#x73B0;&#x5DE5;&#x5177;&#x6765;&#x5F25;&#x8865;&#x8FD9;&#x4E00;&#x7F3A;&#x9677;&#xFF0C;&#x4F46;&#x8FD9;&#x79CD;&#x65B9;&#x5F0F;&#x672C;&#x8D28;&#x4E0A;&#x5177;&#x6709;&#x5C40;&#x9650;&#x6027;&#x3002;&#x5B83;&#x5047;&#x8BBE;LLM&#x65E0;&#x6CD5;&#x5E94;&#x5BF9;&#x73B0;&#x5B9E;&#x4E16;&#x754C;&#x63A5;&#x53E3;&#x7684;&#x590D;&#x6742;&#x6027;&#xFF0C;&#x9700;&#x8981;&#x4EBA;&#x7C7B;&#x4E3A;AI&#x9884;&#x5148;&#x5305;&#x88C5;&#x4E16;&#x754C;&#x3002;&#x8FD9;&#x9887;&#x5177;&#x8BBD;&#x523A;&#x2014;&#x2014;LLM&#x88AB;&#x8A89;&#x4E3A;&#x95EE;&#x9898;&#x89E3;&#x51B3;&#x8005;&#xFF0C;&#x4F46;MCP&#x5374;&#x6697;&#x793A;&#x5B83;&#x4EEC;&#x9700;&#x8981;&#x88AB;&#x7B80;&#x5316;&#x4E16;&#x754C;&#x624D;&#x80FD;&#x6709;&#x6548;&#x8FD0;&#x4F5C;&#x3002;</p><h3 id="%E7%B1%BB%E6%AF%94%EF%BC%9A%E8%87%AA%E5%8A%A8%E9%A9%BE%E9%A9%B6%E6%B1%BD%E8%BD%A6%E4%B8%8E%E5%9F%BA%E7%A1%80%E8%AE%BE%E6%96%BD">&#x7C7B;&#x6BD4;&#xFF1A;&#x81EA;&#x52A8;&#x9A7E;&#x9A76;&#x6C7D;&#x8F66;&#x4E0E;&#x57FA;&#x7840;&#x8BBE;&#x65BD;</h3><p>&#x4E3A;&#x4E86;&#x8BF4;&#x660E;MCP&#x7684;&#x7F3A;&#x9677;&#xFF0C;&#x6211;&#x4EEC;&#x53EF;&#x4EE5;&#x53C2;&#x8003;&#x81EA;&#x52A8;&#x9A7E;&#x9A76;&#x6C7D;&#x8F66;&#x7684;&#x53D1;&#x5C55;&#xFF0C;&#x8FD9;&#x63D0;&#x4F9B;&#x4E86;&#x4E00;&#x4E2A;&#x9C9C;&#x660E;&#x7684;&#x7C7B;&#x6BD4;&#x3002;&#x5B9E;&#x73B0;&#x81EA;&#x52A8;&#x9A7E;&#x9A76;&#x7684;&#x4E00;&#x79CD;&#x65B9;&#x6CD5;&#x662F;&#x521B;&#x5EFA;&#x8F66;&#x8F86;&#x4E0E;&#x9053;&#x8DEF;&#x4E4B;&#x95F4;&#x7684;&#x6807;&#x51C6;&#x5316;&#x901A;&#x4FE1;&#x7CFB;&#x7EDF;&#x2014;&#x2014;&#x667A;&#x80FD;&#x57FA;&#x7840;&#x8BBE;&#x65BD;&#xFF0C;&#x5305;&#x62EC;&#x4F20;&#x611F;&#x5668;&#x3001;&#x4FE1;&#x53F7;&#x548C;&#x8F66;&#x8DEF;&#x534F;&#x540C;&#x7F51;&#x7EDC;&#x3002;&#x8FD9;&#x9700;&#x8981;&#x5BF9;&#x5168;&#x7403;&#x4EA4;&#x901A;&#x7CFB;&#x7EDF;&#x8FDB;&#x884C;&#x5F7B;&#x5E95;&#x6539;&#x9020;&#xFF0C;&#x6210;&#x672C;&#x9AD8;&#x6602;&#x3001;&#x590D;&#x6742;&#x65E0;&#x6BD4;&#xFF0C;&#x88AB;&#x5E7F;&#x6CDB;&#x8BA4;&#x4E3A;&#x4E0D;&#x53EF;&#x884C;&#x3002;&#x76F8;&#x53CD;&#xFF0C;&#x4E3B;&#x6D41;&#x65B9;&#x6CD5;&#x662F;&#x5C06;&#x667A;&#x80FD;&#x5D4C;&#x5165;&#x8F66;&#x8F86;&#x672C;&#x8EAB;&#x3002;&#x901A;&#x8FC7;&#x6444;&#x50CF;&#x5934;&#x3001;&#x96F7;&#x8FBE;&#x548C;AI&#xFF0C;&#x6C7D;&#x8F66;&#x50CF;&#x4EBA;&#x7C7B;&#x4E00;&#x6837;&#x89E3;&#x8BFB;&#x73B0;&#x6709;&#x9053;&#x8DEF;&#x3001;&#x6807;&#x5FD7;&#x548C;&#x4EA4;&#x901A;&#x6A21;&#x5F0F;&#xFF0C;&#x9002;&#x5E94;&#x4E16;&#x754C;&#x800C;&#x65E0;&#x9700;&#x91CD;&#x65B0;&#x8BBE;&#x8BA1;&#x3002;</p><p>MCP&#x7C7B;&#x4F3C;&#x4E8E;&#x4E0D;&#x592A;&#x5B9E;&#x9645;&#x7684;&#x81EA;&#x52A8;&#x9A7E;&#x9A76;&#x65B9;&#x6CD5;&#x3002;&#x901A;&#x8FC7;&#x521B;&#x5EFA;&#x6807;&#x51C6;&#x5316;&#x534F;&#x8BAE;&#xFF0C;&#x5B83;&#x8BD5;&#x56FE;&#x4E3A;LLM&#x6539;&#x9020;&#x6570;&#x5B57;&#x4E16;&#x754C;&#xFF0C;&#x7C7B;&#x4F3C;&#x4E8E;&#x4E3A;&#x6C7D;&#x8F66;&#x5EFA;&#x9020;&#x667A;&#x80FD;&#x9053;&#x8DEF;&#x3002;&#x8FD9;&#x7ED9;&#x5F00;&#x53D1;&#x8005;&#x5E26;&#x6765;&#x4E86;&#x6C89;&#x91CD;&#x7684;&#x8D1F;&#x62C5;&#xFF0C;&#x9700;&#x8981;&#x5C06;&#x5DE5;&#x5177;&#x9002;&#x914D;&#x5230;MCP&#x7684;&#x6846;&#x67B6;&#x4E2D;&#xFF0C;&#x53EF;&#x80FD;&#x4F1A;&#x5F62;&#x6210;&#x4E00;&#x4E2A;&#x5C01;&#x95ED;&#x7684;&#x751F;&#x6001;&#xFF0C;&#x53EA;&#x6709;&#x517C;&#x5BB9;MCP&#x7684;&#x7CFB;&#x7EDF;&#x624D;&#x80FD;&#x88AB;&#x8BBF;&#x95EE;&#x3002;&#x76F8;&#x6BD4;&#x4E4B;&#x4E0B;&#xFF0C;LLM&#x53EF;&#x4EE5;&#x6548;&#x4EFF;&#x8F66;&#x8F86;&#x7AEF;&#x7684;&#x667A;&#x80FD;&#x6A21;&#x5F0F;&#xFF0C;&#x4F9D;&#x9760;&#x5176;&#x4EE3;&#x7801;&#x751F;&#x6210;&#x548C;&#x63A8;&#x7406;&#x80FD;&#x529B;&#xFF0C;&#x76F4;&#x63A5;&#x5BFC;&#x822A;API&#x3001;&#x89E3;&#x6790;&#x6587;&#x6863;&#x5E76;&#x6267;&#x884C;&#x4EFB;&#x52A1;&#x3002;&#x6B63;&#x5982;&#x57FA;&#x4E8E;&#x89C6;&#x89C9;&#x7684;&#x81EA;&#x52A8;&#x9A7E;&#x9A76;&#x6C7D;&#x8F66;&#x5DF2;&#x88AB;&#x8BC1;&#x660E;&#x66F4;&#x5177;&#x53EF;&#x6269;&#x5C55;&#x6027;&#xFF0C;&#x9002;&#x5E94;&#x73B0;&#x6709;&#x6570;&#x5B57;&#x751F;&#x6001;&#x7684;LLM&#x4E5F;&#x53EF;&#x80FD;&#x8D85;&#x8D8A;MCP&#x7684;&#x53D7;&#x9650;&#x65B9;&#x6CD5;&#x3002;</p><h3 id="llm%E8%87%AA%E4%B8%BB%E6%80%A7%E7%9A%84%E7%90%86%E7%94%B1">LLM&#x81EA;&#x4E3B;&#x6027;&#x7684;&#x7406;&#x7531;</h3><p>MCP&#x7684;&#x66FF;&#x4EE3;&#x65B9;&#x6848;&#x663E;&#x800C;&#x6613;&#x89C1;&#xFF1A;&#x8D4B;&#x4E88;LLM&#x5728;&#x5F53;&#x524D;&#x6570;&#x5B57;&#x73AF;&#x5883;&#x4E2D;&#x4F5C;&#x4E3A;&#x81EA;&#x4E3B;&#x4EE3;&#x7406;&#x8FD0;&#x4F5C;&#x7684;&#x80FD;&#x529B;&#x3002;&#x60F3;&#x8C61;&#x4E00;&#x4E2A;LLM&#x5728;&#x5177;&#x6709;&#x4E92;&#x8054;&#x7F51;&#x8BBF;&#x95EE;&#x6743;&#x9650;&#x7684;&#x865A;&#x62DF;&#x673A;&#x4E2D;&#x8FD0;&#x884C;&#xFF0C;&#x80FD;&#x591F;&#x6D4F;&#x89C8;&#x6587;&#x6863;&#x3001;&#x4E0B;&#x8F7D;&#x5DE5;&#x5177;&#x3001;&#x751F;&#x6210;&#x4EE3;&#x7801;&#x3001;&#x7F16;&#x8BD1;&#x5E76;&#x6267;&#x884C;&#x5B83;&#x3002;&#x8FD9;&#x6837;&#x7684;&#x4EE3;&#x7406;&#x65E0;&#x9700;&#x7B80;&#x5316;&#x7684;&#x534F;&#x8BAE;&#x2014;&#x2014;&#x5B83;&#x5C06;&#x5B66;&#x4F1A;&#x8C03;&#x7528;API&#x3001;&#x5904;&#x7406;&#x9519;&#x8BEF;&#x5E76;&#x9002;&#x5E94;&#x65B0;&#x7CFB;&#x7EDF;&#xFF0C;&#x5C31;&#x50CF;&#x4EBA;&#x7C7B;&#x7A0B;&#x5E8F;&#x5458;&#x4E00;&#x6837;&#x3002;&#x8FD9;&#x4E00;&#x613F;&#x666F;&#x4E0E;AI&#x7684;&#x6700;&#x65B0;&#x8D8B;&#x52BF;&#x76F8;&#x7B26;&#x3002;&#x622A;&#x81F3;2025&#x5E74;&#xFF0C;&#x4EE3;&#x7406;&#x578B;AI&#x7CFB;&#x7EDF;&#xFF08;&#x4F8B;&#x5982;AutoGPT&#x7684;&#x7EE7;&#x4EFB;&#x8005;&#xFF09;&#x5DF2;&#x5C55;&#x73B0;&#x51FA;&#x6267;&#x884C;&#x590D;&#x6742;&#x5DE5;&#x4F5C;&#x6D41;&#x7684;&#x80FD;&#x529B;&#xFF0C;&#x4ECE;&#x67E5;&#x8BE2;REST API&#x5230;&#x8C03;&#x8BD5;&#x811A;&#x672C;&#xFF0C;&#x65E0;&#x9700;&#x4F9D;&#x8D56;&#x6807;&#x51C6;&#x5316;&#x7684;&#x4E2D;&#x95F4;&#x5C42;&#x3002;</p><p>&#x8FD9;&#x79CD;&#x65B9;&#x6CD5;&#x5145;&#x5206;&#x5229;&#x7528;&#x4E86;LLM&#x7684;&#x4F18;&#x52BF;&#xFF1A;&#x591A;&#x529F;&#x80FD;&#x6027;&#x548C;&#x9002;&#x5E94;&#x6027;&#x3002;&#x4E0E;&#x4EBA;&#x7C7B;&#x4E0D;&#x540C;&#xFF0C;LLM&#x53EF;&#x4EE5;&#x5373;&#x65F6;&#x5904;&#x7406;&#x5927;&#x91CF;&#x6587;&#x6863;&#xFF0C;&#x6309;&#x9700;&#x751F;&#x6210;&#x5B9A;&#x5236;&#x4EE3;&#x7801;&#xFF0C;&#x5E76;&#x5FEB;&#x901F;&#x8FED;&#x4EE3;&#x3002;&#x8981;&#x6C42;&#x50CF;MCP&#x8FD9;&#x6837;&#x7684;&#x534F;&#x8BAE;&#x6765;&#x8C03;&#x89E3;&#x5B83;&#x4EEC;&#x7684;&#x4EA4;&#x4E92;&#xFF0C;&#x524A;&#x5F31;&#x4E86;&#x8FD9;&#x4E9B;&#x80FD;&#x529B;&#xFF0C;&#x8FEB;&#x4F7F;LLM&#x8FDB;&#x5165;&#x4E00;&#x4E2A;&#x9650;&#x5236;&#x5176;&#x6F5C;&#x529B;&#x7684;&#x50F5;&#x5316;&#x6846;&#x67B6;&#x3002;&#x4F8B;&#x5982;&#xFF0C;&#x5728;&#x201C;&#x6C1B;&#x56F4;&#x7F16;&#x7801;&#x201D;&#xFF08;&#x5373;&#x4F11;&#x95F2;&#x7684;&#x63A2;&#x7D22;&#x6027;&#x7F16;&#x7A0B;&#xFF09;&#x4E2D;&#xFF0C;MCP&#x53EF;&#x80FD;&#x901A;&#x8FC7;&#x804A;&#x5929;&#x754C;&#x9762;&#x5B9E;&#x73B0;&#x5FEB;&#x901F;&#x539F;&#x578B;&#x3002;&#x4F46;&#x5BF9;&#x4E8E;&#x4E25;&#x8083;&#x7684;&#x5E94;&#x7528;&#xFF0C;&#x5982;&#x6784;&#x5EFA;&#x751F;&#x4EA7;&#x7EA7;&#x8F6F;&#x4EF6;&#xFF0C;&#x751F;&#x6210;&#x76F4;&#x63A5;&#x8C03;&#x7528;API&#x7684;&#x672C;&#x673A;&#x4EE3;&#x7801;&#x8FDC;&#x66F4;&#x6709;&#x6548;&#x3002;&#x672C;&#x673A;&#x4EE3;&#x7801;&#x907F;&#x514D;&#x4E86;MCP&#x7684;&#x5F00;&#x9500;&#xFF0C;&#x63D0;&#x4F9B;&#x4E86;&#x6807;&#x51C6;&#x5316;&#x534F;&#x8BAE;&#x65E0;&#x6CD5;&#x5339;&#x654C;&#x7684;&#x7CBE;&#x5EA6;&#x548C;&#x7075;&#x6D3B;&#x6027;&#x3002;</p><h3 id="%E5%8F%8D%E5%AF%B9%E6%84%8F%E8%A7%81%E4%B8%8E%E5%B1%80%E9%99%90%E6%80%A7">&#x53CD;&#x5BF9;&#x610F;&#x89C1;&#x4E0E;&#x5C40;&#x9650;&#x6027;</h3><p>MCP&#x7684;&#x652F;&#x6301;&#x8005;&#x53EF;&#x80FD;&#x8BA4;&#x4E3A;&#xFF0C;&#x6807;&#x51C6;&#x5316;&#x80FD;&#x589E;&#x5F3A;&#x5B89;&#x5168;&#x6027;&#x548C;&#x53EF;&#x9760;&#x6027;&#x3002;&#x5982;&#x679C;&#x6CA1;&#x6709;&#x53EF;&#x63A7;&#x7684;&#x63A5;&#x53E3;&#xFF0C;LLM&#x81EA;&#x7531;&#x4E0E;API&#x4EA4;&#x4E92;&#x53EF;&#x80FD;&#x5E26;&#x6765;&#x98CE;&#x9669;&#xFF0C;&#x4F8B;&#x5982;&#x6267;&#x884C;&#x6076;&#x610F;&#x4EE3;&#x7801;&#x6216;&#x8BEF;&#x89E3;&#x590D;&#x6742;&#x7CFB;&#x7EDF;&#x3002;&#x5728;&#x4F01;&#x4E1A;&#x73AF;&#x5883;&#x4E2D;&#xFF0C;MCP&#x7684;&#x7EDF;&#x4E00;&#x6027;&#x53EF;&#x4EE5;&#x7B80;&#x5316;&#x5BA1;&#x8BA1;&#x548C;&#x5408;&#x89C4;&#x6027;&#xFF0C;&#x786E;&#x4FDD;AI&#x884C;&#x4E3A;&#x53EF;&#x8FFD;&#x8E2A;&#x3002;&#x6B64;&#x5916;&#xFF0C;&#x5F53;&#x524D;LLM&#x5E76;&#x975E;&#x5B8C;&#x5168;&#x81EA;&#x4E3B;&#x2014;&#x2014;&#x5B83;&#x4EEC;&#x5728;&#x957F;&#x671F;&#x89C4;&#x5212;&#x548C;&#x8FB9;&#x7F18;&#x60C5;&#x51B5;&#xFF08;&#x5982;&#x6A21;&#x7CCA;&#x7684;API&#x6587;&#x6863;&#x6216;&#x901F;&#x7387;&#x9650;&#x5236;&#xFF09;&#x4E0A;&#x4ECD;&#x6709;&#x56F0;&#x96BE;&#x3002;MCP&#x53EF;&#x80FD;&#x662F;&#x4E00;&#x4E2A;&#x5B9E;&#x7528;&#x7684;&#x8FC7;&#x6E21;&#x65B9;&#x6848;&#xFF0C;&#x4F7F;LLM&#x5728;&#x63A8;&#x7406;&#x80FD;&#x529B;&#x63D0;&#x5347;&#x4E4B;&#x524D;&#x80FD;&#x591F;&#x53D1;&#x6325;&#x4F5C;&#x7528;&#x3002;</p><p>&#x8FD9;&#x4E9B;&#x89C2;&#x70B9;&#x6709;&#x4E00;&#x5B9A;&#x9053;&#x7406;&#xFF0C;&#x4F46;&#x65E0;&#x6CD5;&#x63A9;&#x76D6;MCP&#x7684;&#x7F3A;&#x9677;&#x3002;&#x5B89;&#x5168;&#x95EE;&#x9898;&#x53EF;&#x4EE5;&#x901A;&#x8FC7;&#x6C99;&#x76D2;&#x73AF;&#x5883;&#x6216;&#x5F3A;&#x5927;&#x7684;&#x9519;&#x8BEF;&#x5904;&#x7406;&#x6765;&#x89E3;&#x51B3;&#xFF0C;&#x800C;&#x65E0;&#x9700;&#x4E3A;LLM&#x7B80;&#x5316;&#x4E16;&#x754C;&#x3002;&#x8FC7;&#x6E21;&#x65B9;&#x6848;&#x7684;&#x8BBA;&#x70B9;&#x5728;AI&#x5FEB;&#x901F;&#x53D1;&#x5C55;&#x9762;&#x524D;&#x4E5F;&#x663E;&#x5F97;&#x8106;&#x5F31;&#x3002;&#x968F;&#x7740;LLM&#x5411;&#x66F4;&#x6DF1;&#x5C42;&#x6B21;&#x7684;&#x63A8;&#x7406;&#x6F14;&#x8FDB;&#x2014;&#x2014;&#x53EF;&#x80FD;&#x901A;&#x8FC7;&#x5F3A;&#x5316;&#x5B66;&#x4E60;&#x6216;&#x6301;&#x4E45;&#x8BB0;&#x5FC6;&#x7684;&#x6574;&#x5408;&#x2014;&#x2014;MCP&#x7684;&#x4F5C;&#x7528;&#x5C06;&#x9010;&#x6E10;&#x51CF;&#x5F31;&#x3002;&#x4E3A;&#x4ECA;&#x65E5;&#x5C40;&#x9650;&#x8BBE;&#x8BA1;&#x7684;&#x534F;&#x8BAE;&#xFF0C;&#x660E;&#x5929;&#x53EF;&#x80FD;&#x6210;&#x4E3A;&#x8FC7;&#x65F6;&#x4E4B;&#x7269;&#xFF0C;&#x5C31;&#x50CF;&#x65E9;&#x671F;&#x4F9D;&#x8D56;&#x8F66;&#x9053;&#x6807;&#x8BB0;&#x7684;&#x81EA;&#x52A8;&#x9A7E;&#x9A76;&#x7CFB;&#x7EDF;&#x88AB;&#x57FA;&#x4E8E;&#x89C6;&#x89C9;&#x7684;AI&#x53D6;&#x4EE3;&#x4E00;&#x6837;&#x3002;</p><h3 id="%E5%89%8D%E8%BF%9B%E4%B9%8B%E8%B7%AF">&#x524D;&#x8FDB;&#x4E4B;&#x8DEF;</h3><p>MCP&#x662F;&#x4E00;&#x79CD;&#x8FC7;&#x6E21;&#x6280;&#x672F;&#xFF0C;&#x53CD;&#x6620;&#x4E86;LLM&#x5F53;&#x524D;&#x7684;&#x672A;&#x6210;&#x719F;&#x72B6;&#x6001;&#x3002;&#x5B83;&#x5728;&#x7279;&#x5B9A;&#x573A;&#x666F;&#x4E2D;&#x8868;&#x73B0;&#x51FA;&#x8272;&#xFF0C;&#x5982;&#x4E3A;&#x4F11;&#x95F2;&#x7528;&#x6237;&#x63D0;&#x4F9B;&#x5BF9;&#x8BDD;&#x5DE5;&#x5177;&#xFF0C;&#x4F46;&#x5728;&#x5B9E;&#x73B0;&#x901A;&#x7528;AI&#x7684;&#x5B8F;&#x4F1F;&#x76EE;&#x6807;&#x4E0A;&#x663E;&#x5F97;&#x4E0D;&#x8DB3;&#x3002;&#x6570;&#x5B57;&#x4E16;&#x754C;&#x8FC7;&#x4E8E;&#x590D;&#x6742;&#xFF0C;&#x65E0;&#x6CD5;&#x62BD;&#x8C61;&#x4E3A;&#x5355;&#x4E00;&#x534F;&#x8BAE;&#xFF0C;&#x800C;LLM&#x8FC7;&#x4E8E;&#x5F3A;&#x5927;&#xFF0C;&#x65E0;&#x6CD5;&#x88AB;&#x5355;&#x4E00;&#x534F;&#x8BAE;&#x675F;&#x7F1A;&#x3002;&#x76F8;&#x53CD;&#xFF0C;&#x6211;&#x4EEC;&#x5E94;&#x6295;&#x8D44;&#x4E8E;&#x6A21;&#x4EFF;&#x4EBA;&#x7C7B;&#x7A0B;&#x5E8F;&#x5458;&#x7684;LLM&#xFF1A;&#x6D4F;&#x89C8;&#x7F51;&#x7EDC;&#x3001;&#x5B66;&#x4E60;&#x6587;&#x6863;&#x3001;&#x4E3A;&#x73B0;&#x5B9E;&#x4E16;&#x754C;&#x7CFB;&#x7EDF;&#x91CF;&#x8EAB;&#x5B9A;&#x5236;&#x89E3;&#x51B3;&#x65B9;&#x6848;&#x3002;&#x8FD9;&#x79CD;&#x65B9;&#x6CD5;&#x4E0D;&#x4EC5;&#x6700;&#x5927;&#x5316;&#x4E86;LLM&#x7684;&#x6F5C;&#x529B;&#xFF0C;&#x4E5F;&#x4E0E;AI&#x7684;&#x521D;&#x8877;&#x76F8;&#x7B26;&#x2014;&#x2014;&#x589E;&#x5F3A;&#x800C;&#x975E;&#x9650;&#x5236;&#x4EBA;&#x7C7B;&#x7684;&#x521B;&#x9020;&#x529B;&#x3002;</p><p>&#x81EA;&#x52A8;&#x9A7E;&#x9A76;&#x6C7D;&#x8F66;&#x7684;&#x7C7B;&#x6BD4;&#x63D0;&#x9192;&#x6211;&#x4EEC;&#xFF0C;&#x8FB9;&#x7F18;&#x667A;&#x80FD;&#x2014;&#x2014;&#x65E0;&#x8BBA;&#x662F;&#x8F66;&#x8F86;&#x8FD8;&#x662F;LLM&#x2014;&#x2014;&#x6BD4;&#x6539;&#x9020;&#x4E16;&#x754C;&#x66F4;&#x5177;&#x6269;&#x5C55;&#x6027;&#x3002;&#x6B63;&#x5982;&#x9053;&#x8DEF;&#x4FDD;&#x6301;&#x4E0D;&#x53D8;&#x800C;&#x6C7D;&#x8F66;&#x53D8;&#x5F97;&#x66F4;&#x667A;&#x80FD;&#xFF0C;&#x6570;&#x5B57;&#x751F;&#x6001;&#x4E5F;&#x5E94;&#x7EF4;&#x6301;&#x73B0;&#x72B6;&#xFF0C;&#x7531;LLM&#x9002;&#x5E94;&#x5176;&#x591A;&#x6837;&#x6027;&#x3002;MCP&#x53EF;&#x80FD;&#x63D0;&#x4F9B;&#x77ED;&#x671F;&#x4FBF;&#x5229;&#xFF0C;&#x4F46;&#x672A;&#x6765;&#x5C5E;&#x4E8E;&#x81EA;&#x4E3B;AI&#x4EE3;&#x7406;&#xFF0C;&#x5B83;&#x4EEC;&#x80FD;&#x4EE5;&#x4EBA;&#x7C7B;&#x822C;&#x7684;&#x7075;&#x654F;&#x5EA6;&#x5BFC;&#x822A;&#x4E16;&#x754C;&#x3002;&#x901A;&#x8FC7;&#x62BC;&#x6CE8;&#x4E8E;LLM&#x7684;&#x9002;&#x5E94;&#x6027;&#xFF0C;&#x6211;&#x4EEC;&#x53EF;&#x4EE5;&#x91CA;&#x653E;&#x5B83;&#x4EEC;&#x7684;&#x771F;&#x6B63;&#x6F5C;&#x529B;&#xFF0C;&#x4F7F;MCP&#x6210;&#x4E3A;&#x4E00;&#x4E2A;&#x4E0D;&#x90A3;&#x4E48;&#x96C4;&#x5FC3;&#x52C3;&#x52C3;&#x7684;&#x65F6;&#x4EE3;&#x7684;&#x9057;&#x7269;&#x3002;</p>]]></content:encoded></item><item><title><![CDATA[The Case Against MCP: Why LLMs Should Adapt to the World, Not Vice Versa]]></title><description><![CDATA[<p>The Model Control Protocol (MCP), introduced by Anthropic, is pitched as a universal interface for large language models (LLMs) to interact with the external world&#x2014;a &#x201C;USB-C port&#x201D; through which LLMs can connect to tools, APIs, and systems. At first glance, this standardization seems practical, promising seamless</p>]]></description><link>https://blog.optman.net/the-case-against-mcp-why-llms-should-adapt-to-the-world-not-vice-versa/</link><guid isPermaLink="false">67fa332c8fb9570001168307</guid><category><![CDATA[AI]]></category><dc:creator><![CDATA[optman]]></dc:creator><pubDate>Sat, 12 Apr 2025 09:33:26 GMT</pubDate><content:encoded><![CDATA[<p>The Model Control Protocol (MCP), introduced by Anthropic, is pitched as a universal interface for large language models (LLMs) to interact with the external world&#x2014;a &#x201C;USB-C port&#x201D; through which LLMs can connect to tools, APIs, and systems. At first glance, this standardization seems practical, promising seamless integration for AI in diverse applications. However, a closer examination reveals MCP as a flawed and potentially unnecessary solution. Rather than empowering LLMs to navigate the complex digital ecosystem as humans do, MCP imposes a simplified intermediary layer that reflects current AI limitations and risks becoming obsolete. This essay argues that LLMs should leverage their inherent adaptability to engage directly with existing tools and APIs, drawing on an analogy to self-driving cars and insights from ongoing AI advancements.</p><h3 id="the-promise-and-pitfalls-of-mcp">The Promise and Pitfalls of MCP</h3><p>Anthropic describes MCP as a standardized protocol that enables LLMs to interact with external systems securely and efficiently. Much like a USB-C port allows a computer to connect to various peripherals, MCP aims to streamline how LLMs access databases, APIs, or software tools. For developers, this abstraction could simplify integration, ensuring LLMs operate within a controlled, predictable framework. In scenarios like enterprise workflows or casual chat-based interfaces, MCP&#x2019;s uniformity might reduce complexity, offering a plug-and-play experience for non-technical users or organizations prioritizing security.</p><p>However, the need for a dedicated protocol raises a fundamental question: why should LLMs require a bespoke interface when they are designed to mimic human-like reasoning? LLMs, with their ability to generate code, parse documentation, and adapt to diverse contexts, are uniquely suited to interact with the digital world as it exists. Creating a new protocol like MCP feels akin to building bridges to connect every tool and API to LLMs&#x2014;an inefficient and unsustainable endeavor. The digital ecosystem is vast and fragmented, with countless APIs, formats, and standards. Standardizing this chaos for LLMs is as impractical as rewriting the internet to be AI-friendly.</p><p>Moreover, MCP underscores a deeper issue: the current limitations of LLMs. These models rely heavily on context windows, which provide shallow, transient knowledge rather than deep domain expertise. MCP compensates for this by presenting tools in a simplified, standardized format, but this approach is inherently restrictive. It assumes LLMs cannot handle the complexity of real-world interfaces, requiring humans to pre-package the world for AI consumption. This is ironic&#x2014;LLMs are heralded as problem-solvers, yet MCP suggests they need coddling to function effectively.</p><h3 id="an-analogy-self-driving-cars-and-infrastructure">An Analogy: Self-Driving Cars and Infrastructure</h3><p>To illustrate MCP&#x2019;s flaws, consider the development of self-driving cars, which offers a striking parallel. One approach to autonomy involves creating a standardized communication system between vehicles and roads&#x2014;smart infrastructure with sensors, signals, and vehicle-to-infrastructure networks. This would require overhauling global traffic systems, an undertaking so costly and complex that it&#x2019;s widely deemed unviable. Instead, the prevailing approach embeds intelligence within the vehicle itself. Using cameras, radar, and AI, cars interpret existing roads, signs, and traffic patterns as humans do, adapting to the world without demanding its redesign.</p><p>MCP mirrors the less practical autopilot approach. By creating a standardized protocol, it attempts to retrofit the digital world for LLMs, much like building smart roads for cars. This imposes a heavy burden on developers to adapt tools to MCP&#x2019;s framework, risking a walled garden where only MCP-compatible systems are accessible. In contrast, LLMs could emulate the vehicle-side intelligence model, relying on their code-generation and reasoning capabilities to navigate APIs, parse documentation, and execute tasks directly. Just as vision-based self-driving cars have proven more scalable, LLMs that adapt to the existing digital ecosystem will likely outpace MCP&#x2019;s constrained approach.</p><h3 id="the-case-for-llm-autonomy">The Case for LLM Autonomy</h3><p>The alternative to MCP is clear: empower LLMs to function as autonomous agents within the current digital landscape. Imagine an LLM operating in a virtual machine with internet access, capable of browsing documentation, downloading tools, generating code, compiling it, and executing it. Such an agent would not need a simplified protocol&#x2014;it would learn to call APIs, handle errors, and adapt to new systems, much like a human programmer. This vision aligns with emerging trends in AI. As of 2025, agentic systems&#x2014;successors to tools like AutoGPT&#x2014;are demonstrating the ability to perform complex workflows, from querying REST APIs to debugging scripts, without relying on standardized intermediaries.</p><p>This approach leverages LLMs&#x2019; strengths: their versatility and adaptability. Unlike humans, LLMs can process vast documentation instantly, generate tailored code on demand, and iterate rapidly. Requiring a protocol like MCP to mediate their interactions undermines these capabilities, forcing LLMs into a rigid framework that limits their potential. For example, in &#x201C;vibe coding&#x201D;&#x2014;casual, exploratory programming&#x2014;MCP might enable quick prototypes via chat interfaces. But for serious applications, such as building production-grade software, generating native code that directly calls APIs is far more effective. Native code avoids MCP&#x2019;s overhead, offering precision and flexibility that a standardized protocol cannot match.</p><h3 id="counterpoints-and-limitations">Counterpoints and Limitations</h3><p>Proponents of MCP might argue that standardization enhances security and reliability. Without a controlled interface, LLMs freely interacting with APIs could introduce risks, such as executing malicious code or misinterpreting complex systems. In enterprise settings, MCP&#x2019;s uniformity could simplify auditing and compliance, ensuring AI actions are traceable. Additionally, current LLMs are not fully autonomous&#x2014;they struggle with long-term planning and edge cases, like ambiguous API documentation or rate limits. MCP might serve as a pragmatic stopgap, enabling LLMs to be useful today while their reasoning improves.</p><p>These points have merit, but they don&#x2019;t outweigh MCP&#x2019;s flaws. Security concerns can be addressed through sandboxed environments or robust error-handling, not by simplifying the world for LLMs. The stopgap argument also falters when we consider the pace of AI advancement. As LLMs evolve toward deeper reasoning&#x2014;potentially integrating reinforcement learning or persistent memory&#x2014;MCP&#x2019;s role will diminish. A protocol designed for today&#x2019;s limitations risks obsolescence tomorrow, much like early autopilot systems that relied on lane markers gave way to vision-based AI.</p><h3 id="the-path-forward">The Path Forward</h3><p>MCP is a transitional technology, a reflection of LLMs&#x2019; current adolescence. It excels in niche scenarios, like conversational tools for casual users, but falls short for the ambitious goal of general AI. The digital world is too complex to be abstracted into a single protocol, and LLMs are too capable to be confined by one. Instead, we should invest in LLMs that emulate human programmers: browsing the web, learning from documentation, and crafting solutions tailored to real-world systems. This approach not only maximizes LLMs&#x2019; potential but also aligns with the ethos of AI&#x2014;to augment, not constrain, human ingenuity.</p><p>The self-driving car analogy reminds us that intelligence at the edge&#x2014;whether in a vehicle or an LLM&#x2014;scales better than reengineering the world. Just as roads remain unchanged while cars grow smarter, the digital ecosystem should stand as is, with LLMs adapting to its diversity. MCP may offer short-term convenience, but the future belongs to autonomous AI agents that navigate the world with the same dexterity as their human counterparts. By betting on LLMs&#x2019; adaptability, we can unlock their true potential, rendering protocols like MCP relics of a less ambitious era.</p>]]></content:encoded></item><item><title><![CDATA[LLM 真的能学会算术吗？]]></title><description><![CDATA[<h2></h2><p>&#x53D7; DeepSeek R1 &#x91C7;&#x7528;&#x5F3A;&#x5316;&#x5B66;&#x4E60;&#xFF08;RL&#xFF09;&#x8BAD;&#x7EC3;&#x7684;&#x6210;&#x529F;&#x542F;&#x53D1;&#xFF0C;&#x6211;&#x51B3;&#x5B9A;&#x91CD;&#x65B0;&#x63A2;&#x7D22; RL &#x6280;&#x672F;&#x3002;&#x56DB;&#x5E74;&#x524D;&#xFF0C;AlphaGo &#x6218;&#x80DC;&#x4EBA;&#x7C7B;&#x68CB;&#x624B;&#x65F6;&#xFF0C;&#x6211;&#x66FE;&#x5BF9; RL &#x4EA7;&#x751F;</p>]]></description><link>https://blog.optman.net/can-llms-really-learn-arithmetic-chinese/</link><guid isPermaLink="false">67dbf7238fb95700011682d6</guid><category><![CDATA[AI]]></category><category><![CDATA[LLM]]></category><dc:creator><![CDATA[optman]]></dc:creator><pubDate>Thu, 20 Mar 2025 13:20:15 GMT</pubDate><content:encoded><![CDATA[<h2></h2><p>&#x53D7; DeepSeek R1 &#x91C7;&#x7528;&#x5F3A;&#x5316;&#x5B66;&#x4E60;&#xFF08;RL&#xFF09;&#x8BAD;&#x7EC3;&#x7684;&#x6210;&#x529F;&#x542F;&#x53D1;&#xFF0C;&#x6211;&#x51B3;&#x5B9A;&#x91CD;&#x65B0;&#x63A2;&#x7D22; RL &#x6280;&#x672F;&#x3002;&#x56DB;&#x5E74;&#x524D;&#xFF0C;AlphaGo &#x6218;&#x80DC;&#x4EBA;&#x7C7B;&#x68CB;&#x624B;&#x65F6;&#xFF0C;&#x6211;&#x66FE;&#x5BF9; RL &#x4EA7;&#x751F;&#x6781;&#x5927;&#x5174;&#x8DA3;&#x3002;&#x7136;&#x800C;&#xFF0C;&#x5C3D;&#x7BA1; OpenAI &#x65E9;&#x5728;&#x51E0;&#x5E74;&#x524D;&#x5C31;&#x5728; ChatGPT &#x8BAD;&#x7EC3;&#x4E2D;&#x5E94;&#x7528;&#x4E86; RL&#xFF08;&#x5C24;&#x5176;&#x662F; RLHF&#xFF09;&#xFF0C;&#x6211;&#x59CB;&#x7EC8;&#x672A;&#x80FD;&#x5B8C;&#x5168;&#x7406;&#x89E3; RL &#x5728; LLM &#x8BAD;&#x7EC3;&#x4E2D;&#x7684;&#x5177;&#x4F53;&#x5E94;&#x7528;&#x65B9;&#x5F0F;&#x3002;</p><p><a href="https://blog.optman.net/donkeycar-rl/">&#x51E0;&#x5E74;&#x524D;</a>&#xFF0C;&#x6211;&#x66FE;&#x5728;&#x6811;&#x8393;&#x6D3E;&#xFF08;Raspberry Pi&#xFF09;&#x9A71;&#x52A8;&#x7684; Donkey &#x673A;&#x5668;&#x4EBA;&#x5C0F;&#x8F66;&#x4E0A;&#x5C1D;&#x8BD5;&#x8FC7; RL &#x8BAD;&#x7EC3;&#xFF0C;&#x4F46;&#x6548;&#x679C;&#x4E0D;&#x4F73;&#x3002;&#x5C3D;&#x7BA1;&#x6211;&#x5BF9; RL &#x7684;&#x6F5C;&#x529B;&#x6709;&#x6240;&#x9886;&#x609F;&#xFF0C;&#x4F46;&#x4E5F;&#x6DF1;&#x77E5;&#x5176;&#x5C40;&#x9650;&#x6027;&#x3002;</p><p>&#x5728;&#x9605;&#x8BFB;&#x4E86; DeepSeek &#x76F8;&#x5173;&#x8BBA;&#x6587;&#x540E;&#xFF0C;&#x6211;&#x5BF9;&#x4ED6;&#x4EEC;&#x53D1;&#x660E;&#x7684; <strong>GRPO&#xFF08;Group Relative Policy Optimization&#xFF09;</strong> &#x6DF1;&#x611F;&#x5174;&#x8DA3;&#x3002;GRPO &#x901A;&#x8FC7;&#x6D88;&#x9664;&#x4EF7;&#x503C;&#x7F51;&#x7EDC;&#xFF0C;&#x5927;&#x5927;&#x7B80;&#x5316;&#x4E86; RL &#x65B9;&#x6CD5;&#x3002;&#x6211;&#x968F;&#x540E;&#x9605;&#x8BFB;&#x4E86; <a href="https://github.com/huggingface/trl">huggingface/trl</a> &#x548C; tinyzero &#x7B49;&#x9879;&#x76EE;&#x7684; GRPO &#x4EE3;&#x7801;&#x3002;&#x867D;&#x7136;&#x6838;&#x5FC3;&#x4EE3;&#x7801;&#x76F8;&#x5BF9;&#x7B80;&#x5355;&#xFF0C;&#x4F46;&#x5927;&#x91CF;&#x7684;&#x652F;&#x6491;&#x4EE3;&#x7801;&#xFF08;scaffold code&#xFF09;&#x4F7F;&#x5B9E;&#x73B0;&#x8FC7;&#x7A0B;&#x53D8;&#x5F97;&#x7E41;&#x7410;&#x3002;&#x6B63;&#x5982;&#x79D1;&#x5B66;&#x5BB6;&#x6240;&#x8A00;&#xFF0C;<strong>&#x7406;&#x89E3;&#x4E16;&#x754C;&#x6700;&#x597D;&#x7684;&#x65B9;&#x5F0F;&#x5C31;&#x662F;&#x4EB2;&#x624B;&#x6784;&#x5EFA;&#x5B83;</strong>&#x3002;</p><p>&#x56E0;&#x6B64;&#xFF0C;&#x6211;&#x51B3;&#x5B9A;<strong>&#x81EA;&#x5DF1;&#x590D;&#x73B0; GRPO</strong>&#xFF0C;&#x5E76;&#x5C06;&#x5176;&#x6784;&#x5EFA;&#x5728;&#x6211;&#x4E24;&#x5E74;&#x524D;&#x5F00;&#x53D1;&#x7684; <strong><a href="https://github.com/optman/nanogpt-rs">nanoGPT-rs</a> &#x9879;&#x76EE;&#x4E4B;&#x4E0A;&#x3002;nanoGPT-rs &#x662F; <a href="https://github.com/karpathy/nanoGPT">nanoGPT</a> &#x7684; Rust &#x590D;&#x523B;&#x7248;</strong>&#x3002;&#x901A;&#x8FC7;&#x4ECE;&#x96F6;&#x5B9E;&#x73B0; LLM&#xFF0C;&#x6211;&#x80FD;&#x591F;&#x5F7B;&#x5E95;&#x7406;&#x89E3;&#x57FA;&#x4E8E; Transformer &#x7684;&#x67B6;&#x6784;&#x3002;&#x6B64;&#x5916;&#xFF0C;&#x6211;&#x975E;&#x5E38;&#x559C;&#x6B22; <strong><a href="https://github.com/coreylowman/dfdx">dfdx</a></strong> &#x8FD9;&#x4E2A; Rust &#x673A;&#x5668;&#x5B66;&#x4E60;&#x6846;&#x67B6;&#xFF0C;&#x5B83;&#x7C7B;&#x4F3C;&#x4E8E; PyTorch&#xFF0C;&#x4F46;&#x80FD;&#x591F;&#x5728;<strong>&#x7F16;&#x8BD1;&#x65F6;&#x9759;&#x6001;&#x68C0;&#x67E5;&#x5F20;&#x91CF;&#x5F62;&#x72B6;</strong>&#xFF0C;&#x786E;&#x4FDD;&#x4EE3;&#x7801;&#x6B63;&#x786E;&#x3002;&#x8FD9;&#x79CD;&#x5F3A;&#x5236;&#x6027;&#x7EA6;&#x675F;&#x5E2E;&#x52A9;&#x6211;&#x66F4;&#x597D;&#x5730;&#x7406;&#x89E3;&#x795E;&#x7ECF;&#x7F51;&#x7EDC;&#x7EC4;&#x4EF6;&#x4E4B;&#x95F4;&#x7684;&#x4EA4;&#x4E92;&#x5173;&#x7CFB;&#x3002;&#x8FD9;&#x4E5F;&#x662F; Rust &#x4E0E; Python &#x5728;&#x5F00;&#x53D1;&#x4F53;&#x9A8C;&#x4E0A;&#x7684;&#x4E00;&#x5927;&#x4E0D;&#x540C;&#x4E4B;&#x5904;&#x3002;&#x9057;&#x61BE;&#x7684;&#x662F;&#xFF0C;dfdx &#x76EE;&#x524D;&#x7684;&#x5F00;&#x53D1;&#x5DF2;&#x7ECF;&#x505C;&#x6B62;&#x4E86;&#x3002;</p><h3 id="%E5%AE%9E%E9%AA%8C%E7%9B%AE%E6%A0%87"><strong>&#x5B9E;&#x9A8C;&#x76EE;&#x6807;</strong></h3><p>&#x6211;&#x7684;&#x76EE;&#x6807;&#x662F;<strong>&#x8BAD;&#x7EC3; LLM &#x5B66;&#x4E60;&#x7B80;&#x5355;&#x7684;&#x6570;&#x5B57;&#x52A0;&#x6CD5;</strong>&#x3002;&#x8FD9;&#x770B;&#x4F3C;&#x662F;&#x4E00;&#x4E2A;&#x7B80;&#x5355;&#x7684;&#x4EFB;&#x52A1;&#xFF0C;&#x4F46;&#x5B9E;&#x9645;&#x4E0A;&#x5E76;&#x4E0D;&#x5BB9;&#x6613;&#x3002;&#x5373;&#x4FBF;&#x662F;&#x6700;&#x5148;&#x8FDB;&#x7684;&#x6A21;&#x578B;&#xFF08;&#x5982; GPT-4&#xFF09;&#xFF0C;&#x6709;&#x65F6;&#x4ECD;&#x7136;&#x4F1A;&#x5728;&#x57FA;&#x672C;&#x7B97;&#x672F;&#x8FD0;&#x7B97;&#x4E0A;&#x51FA;&#x9519;&#x3002;&#x800C;&#x4E14;&#xFF0C;&#x6211;&#x4EEC;&#x4ECD;&#x4E0D;&#x6E05;&#x695A; LLM <strong>&#x7A76;&#x7ADF;&#x662F;&#x5728;&#x5B66;&#x4E60;&#x7B97;&#x672F;&#x89C4;&#x5219;&#xFF0C;&#x8FD8;&#x662F;&#x4EC5;&#x4EC5;&#x5728;&#x8BB0;&#x5FC6;&#x8BAD;&#x7EC3;&#x6570;&#x636E;&#x4E2D;&#x7684;&#x52A0;&#x6CD5;&#x7ED3;&#x679C;</strong>&#x3002;</p><p>&#x4E3A;&#x4E86;&#x7B80;&#x5316;&#x4EFB;&#x52A1;&#xFF0C;&#x6211;&#x7684;&#x6A21;&#x578B;&#x4EC5;&#x9700;<strong>&#x9884;&#x6D4B;&#x52A0;&#x6CD5;&#x7684;&#x8FD0;&#x7B97;&#x7ED3;&#x679C;</strong>&#xFF0C;&#x800C;&#x4E0D;&#x6D89;&#x53CA;&#x5176;&#x4ED6;&#x6587;&#x672C;&#x751F;&#x6210;&#x3002;&#x6211;&#x91C7;&#x7528; Python &#x811A;&#x672C;&#x751F;&#x6210;&#x8BAD;&#x7EC3;&#x6570;&#x636E;&#xFF0C;&#x5305;&#x542B;&#xFF1A;</p><ul><li><strong>&#x4E24;&#x4E2A; 1 &#x4F4D;&#x6570;&#x76F8;&#x52A0;</strong>&#xFF08;&#x5982; 2+1=3&#xFF09;</li><li><strong>&#x4E24;&#x4E2A; 2 &#x4F4D;&#x6570;&#x76F8;&#x52A0;</strong>&#xFF08;&#x5982; 11+12=23&#xFF09;</li><li><strong>&#x4E09;&#x4E2A; 1 &#x4F4D;&#x6570;&#x76F8;&#x52A0;&#xFF0C;&#x5E76;&#x52A0;&#x5165;&#x4E2D;&#x95F4;&#x6B65;&#x9AA4;</strong>&#xFF08;&#x5982; 1+1+1=2+1=3&#xFF09;</li></ul><p>&#x6A21;&#x578B;&#x7684;&#x8F93;&#x5165;&#x683C;&#x5F0F;&#x5982;&#x4E0B;&#xFF1A;</p><pre><code>2+1=  
11+12=  
1+1+1=  
</code></pre><h3 id="%E5%AE%9E%E9%AA%8C%E7%BB%93%E6%9E%9C"><strong>&#x5B9E;&#x9A8C;&#x7ED3;&#x679C;</strong></h3><ul><li>&#x7ECF;&#x8FC7;&#x9884;&#x8BAD;&#x7EC3;&#xFF08;pre-training&#xFF09;&#xFF0C;&#x6A21;&#x578B;&#x53EF;&#x4EE5;&#x5728;<strong>&#x5C11;&#x91CF;&#x8BAD;&#x7EC3;&#x5468;&#x671F;&#x5185;&#x8FC5;&#x901F;&#x8FBE;&#x5230;&#x9AD8;&#x51C6;&#x786E;&#x7387;</strong>&#xFF0C;&#x4F46;&#x968F;&#x540E;&#x7CBE;&#x5EA6;<strong>&#x505C;&#x6EDE;</strong>&#x3002;</li><li>&#x7EE7;&#x7EED;&#x91C7;&#x7528; RL &#x8BAD;&#x7EC3;&#x540E;&#xFF0C;&#x51C6;&#x786E;&#x7387;<strong>&#x6709;&#x6240;&#x63D0;&#x5347;</strong>&#x3002;</li><li><strong>&#x5373;&#x4F7F;&#x51C6;&#x786E;&#x7387;&#x63A5;&#x8FD1; 100%&#xFF0C;&#x6A21;&#x578B;&#x4ECD;&#x53EF;&#x80FD;&#x5728;&#x672A;&#x89C1;&#x8FC7;&#x7684;&#x6837;&#x672C;&#x4E0A;&#x51FA;&#x9519;</strong>&#x3002;</li><li>&#x8FD9;&#x8868;&#x660E; LLM <strong>&#x5E76;&#x6CA1;&#x6709;&#x771F;&#x6B63;&#x5B66;&#x4F1A;&#x52A0;&#x6CD5;&#x89C4;&#x5219;&#xFF0C;&#x800C;&#x662F;&#x901A;&#x8FC7;&#x67D0;&#x79CD;&#x8FD1;&#x4F3C;&#x65B9;&#x6CD5;&#x8FDB;&#x884C;&#x63A8;&#x7406;</strong>&#x3002;&#x4F46;&#x8FD9;&#x79CD;&#x65B9;&#x6CD5;&#x4E0E;&#x4EBA;&#x7C7B;&#x7684;&#x6570;&#x5B66;&#x63A8;&#x7406;&#x65B9;&#x5F0F;&#x5B8C;&#x5168;&#x4E0D;&#x540C;&#x3002;</li></ul><hr><h2 id="%E6%88%91%E7%9A%84%E6%80%9D%E8%80%83%E4%B8%8E%E6%94%B6%E8%8E%B7"><strong>&#x6211;&#x7684;&#x601D;&#x8003;&#x4E0E;&#x6536;&#x83B7;</strong></h2><h3 id="1-llm-%E4%B8%8D%E4%BC%9A%E2%80%9C%E8%87%AA%E5%8A%A8%E2%80%9D%E5%AD%A6%E4%BC%9A%E7%AE%97%E6%9C%AF%E8%A7%84%E5%88%99"><strong>1. LLM &#x4E0D;&#x4F1A;&#x201C;&#x81EA;&#x52A8;&#x201D;&#x5B66;&#x4F1A;&#x7B97;&#x672F;&#x89C4;&#x5219;</strong></h3><p>LLM <strong>&#x4E0D;&#x4F1A;&#x81EA;&#x7136;&#x5730;&#x5B66;&#x4E60;&#x7B97;&#x672F;&#x6CD5;&#x5219;</strong>&#xFF0C;&#x800C;&#x662F;&#x901A;&#x8FC7;&#x67D0;&#x79CD;&#x65B9;&#x5F0F;&#x8FD1;&#x4F3C;&#x8BA1;&#x7B97;&#x7ED3;&#x679C;&#x3002;&#x8FD9;&#x79CD;&#x65B9;&#x6CD5;<strong>&#x4E0D;&#x4E00;&#x5B9A;&#x7B26;&#x5408;&#x4EBA;&#x7C7B;&#x7684;&#x7B97;&#x672F;&#x89C4;&#x5219;</strong>&#xFF0C;&#x56E0;&#x6B64; LLM &#x7684;&#x8FD0;&#x7B97;&#x7ED3;&#x679C;&#x5E76;&#x975E; 100% &#x6B63;&#x786E;&#xFF0C;&#x4E14;&#x5728;&#x67D0;&#x4E9B;&#x60C5;&#x51B5;&#x4E0B;<strong>&#x53EF;&#x80FD;&#x4E0D;&#x53EF;&#x9884;&#x6D4B;</strong>&#x3002;</p><h3 id="2-%E8%BF%87%E6%8B%9F%E5%90%88%E6%98%AF%E4%B8%80%E4%B8%AA%E4%B8%A5%E9%87%8D%E9%97%AE%E9%A2%98"><strong>2. &#x8FC7;&#x62DF;&#x5408;&#x662F;&#x4E00;&#x4E2A;&#x4E25;&#x91CD;&#x95EE;&#x9898;</strong></h3><p>&#x5BF9;&#x4E8E;&#x7B80;&#x5355;&#x7684;&#x52A0;&#x6CD5;&#x4EFB;&#x52A1;&#xFF0C;LLM &#x5F88;&#x5BB9;&#x6613;<strong>&#x8FC7;&#x62DF;&#x5408;</strong>&#x8BAD;&#x7EC3;&#x6570;&#x636E;&#x3002;&#x56E0;&#x6B64;&#xFF0C;<strong>&#x4F7F;&#x7528;&#x5C0F;&#x578B;&#x6A21;&#x578B;</strong>&#x53EF;&#x4EE5;&#x51CF;&#x5C11;&#x8FC7;&#x62DF;&#x5408;&#xFF0C;&#x5E76;&#x4E14; RL &#x8BAD;&#x7EC3;&#x80FD;&#x591F;&#x4FC3;&#x4F7F;&#x6A21;&#x578B;<strong>&#x5B66;&#x4E60;&#x5E95;&#x5C42;&#x89C4;&#x5F8B;&#xFF0C;&#x800C;&#x4E0D;&#x662F;&#x6B7B;&#x8BB0;&#x786C;&#x80CC;&#x7ED3;&#x679C;</strong>&#x3002;</p><h3 id="3-rl-%E8%AE%AD%E7%BB%83%E4%BE%9D%E8%B5%96%E5%A4%A7%E9%87%8F%E8%AF%95%E9%94%99"><strong>3. RL &#x8BAD;&#x7EC3;&#x4F9D;&#x8D56;&#x5927;&#x91CF;&#x8BD5;&#x9519;</strong></h3><p>RL &#x8BAD;&#x7EC3;&#x9700;&#x8981;<strong>&#x968F;&#x673A;&#x8BD5;&#x9519;</strong>&#x6765;&#x627E;&#x5230;&#x6B63;&#x786E;&#x7B54;&#x6848;&#xFF0C;&#x56E0;&#x6B64;&#x5B83;&#x901A;&#x5E38;&#x9700;&#x8981;&#x6BD4;&#x9884;&#x8BAD;&#x7EC3;&#x66F4;&#x591A;&#x7684;&#x8BA1;&#x7B97;&#x65F6;&#x95F4;&#x3002;&#x7136;&#x800C;&#xFF0C;&#x5728;&#x8DB3;&#x591F;&#x957F;&#x7684;&#x8BAD;&#x7EC3;&#x65F6;&#x95F4;&#x540E;&#xFF0C;RL <strong>&#x80FD;&#x591F;&#x8FDB;&#x4E00;&#x6B65;&#x63D0;&#x9AD8;&#x6A21;&#x578B;&#x7684;&#x51C6;&#x786E;&#x6027;</strong>&#x3002;</p><h3 id="4-%E6%9C%80%E4%BC%98%E7%AD%96%E7%95%A5%EF%BC%9A%E5%85%88%E9%A2%84%E8%AE%AD%E7%BB%83%EF%BC%8C%E5%86%8D%E5%BC%BA%E5%8C%96%E5%AD%A6%E4%B9%A0"><strong>4. &#x6700;&#x4F18;&#x7B56;&#x7565;&#xFF1A;&#x5148;&#x9884;&#x8BAD;&#x7EC3;&#xFF0C;&#x518D;&#x5F3A;&#x5316;&#x5B66;&#x4E60;</strong></h3><p><strong>&#x5148;&#x9884;&#x8BAD;&#x7EC3;&#xFF0C;&#x518D;&#x8FDB;&#x884C; RL &#x8BAD;&#x7EC3;</strong>&#x662F;&#x66F4;&#x6709;&#x6548;&#x7684;&#x65B9;&#x6CD5;&#x3002;</p><ul><li><strong>&#x9884;&#x8BAD;&#x7EC3;</strong>&#x53EF;&#x4EE5;&#x8BA9;&#x6A21;&#x578B;&#x638C;&#x63E1;&#x57FA;&#x672C;&#x89C4;&#x5219;&#xFF0C;&#x4F8B;&#x5982;&#x786E;&#x4FDD;&#x8F93;&#x51FA;&#x4E3A;&#x6570;&#x5B57;&#xFF0C;&#x4ECE;&#x800C;<strong>&#x51CF;&#x5C11; RL &#x8BAD;&#x7EC3;&#x7684;&#x63A2;&#x7D22;&#x7A7A;&#x95F4;</strong>&#xFF0C;&#x52A0;&#x5FEB;&#x6536;&#x655B;&#x901F;&#x5EA6;&#x3002;</li><li><strong>&#x4F46;&#x5982;&#x679C;&#x9884;&#x8BAD;&#x7EC3;&#x65F6;&#x95F4;&#x8FC7;&#x957F;&#xFF0C;&#x6A21;&#x578B;&#x53EF;&#x80FD;&#x4F1A;&#x8FC7;&#x62DF;&#x5408;&#x8BAD;&#x7EC3;&#x6570;&#x636E;</strong>&#xFF0C;&#x5BFC;&#x81F4; RL &#x8BAD;&#x7EC3;&#x65F6;&#x96BE;&#x4EE5;&#x63A2;&#x7D22;&#x65B0;&#x7684;&#x89C4;&#x5219;&#x3002;&#x5982;&#x679C;&#x6A21;&#x578B;&#x5728;&#x9884;&#x8BAD;&#x7EC3;&#x9636;&#x6BB5;&#x5B66;&#x9519;&#x4E86;&#x7B97;&#x672F;&#x89C4;&#x5219;&#xFF0C;&#x5B83;&#x5C06;&#x5F88;&#x96BE;<strong>&#x9057;&#x5FD8;&#x9519;&#x8BEF;&#x7684;&#x89C4;&#x5219;</strong>&#xFF0C;&#x5E76;&#x5B66;&#x4F1A;&#x6B63;&#x786E;&#x7684;&#x89C4;&#x5219;&#x3002;&#x8FD9;&#x662F;&#x7531;&#x4E8E;&#x795E;&#x7ECF;&#x7F51;&#x7EDC;&#x7684;<strong>&#x5C40;&#x90E8;&#x68AF;&#x5EA6;&#x4E0B;&#x964D;</strong>&#x7279;&#x6027;&#xFF0C;&#x4F7F;&#x5176;&#x96BE;&#x4EE5;&#x8DF3;&#x51FA;&#x5C40;&#x90E8;&#x6700;&#x4F18;&#x89E3;&#x3002;</li></ul><h3 id="5-%E6%95%B0%E6%8D%AE%E5%A4%9A%E6%A0%B7%E6%80%A7%E5%AF%B9%E4%BA%8E%E6%B3%9B%E5%8C%96%E8%87%B3%E5%85%B3%E9%87%8D%E8%A6%81"><strong>5. &#x6570;&#x636E;&#x591A;&#x6837;&#x6027;&#x5BF9;&#x4E8E;&#x6CDB;&#x5316;&#x81F3;&#x5173;&#x91CD;&#x8981;</strong></h3><p>&#x8BAD;&#x7EC3;&#x6570;&#x636E;&#x7684;<strong>&#x591A;&#x6837;&#x6027;</strong>&#x81F3;&#x5173;&#x91CD;&#x8981;&#xFF0C;&#x5B83;&#x80FD;&#x591F;&#x9632;&#x6B62;&#x8FC7;&#x62DF;&#x5408;&#x3002;&#x6A21;&#x578B;&#x8D8A;&#x5927;&#xFF0C;&#x5BF9;&#x6570;&#x636E;&#x7684;&#x591A;&#x6837;&#x6027;&#x8981;&#x6C42;&#x4E5F;&#x5C31;&#x8D8A;&#x9AD8;&#x3002;&#x5982;&#x679C;&#x4E00;&#x4E2A;&#x6A21;&#x578B;<strong>&#x8FC7;&#x65E9;&#x5BF9;&#x7279;&#x5B9A;&#x6A21;&#x5F0F;&#x4EA7;&#x751F;&#x81EA;&#x4FE1;</strong>&#xFF0C;&#x5B83;&#x4F1A;&#x505C;&#x6B62;&#x63A2;&#x7D22;&#xFF0C;&#x4ECE;&#x800C;&#x65E0;&#x6CD5;&#x6CDB;&#x5316;&#x3002;</p><p><strong>&#x597D;&#x7684;&#x5B66;&#x4E60;&#x66F2;&#x7EBF;&#x5E94;&#x8BE5;&#x5728;&#x4E2D;&#x671F;&#x6709;&#x4E00;&#x4E2A;&#x7A81;&#x589E;</strong>&#x3002;&#x5982;&#x679C;&#x6A21;&#x578B;&#x7684;&#x51C6;&#x786E;&#x7387;&#x662F;<strong>&#x7EBF;&#x6027;&#x589E;&#x957F;&#x7684;</strong>&#xFF0C;&#x90A3;&#x4E48;&#x5B83;&#x5F88;&#x53EF;&#x80FD;<strong>&#x53EA;&#x662F;&#x5728;&#x8FC7;&#x62DF;&#x5408;</strong>&#xFF0C;&#x800C;&#x65E0;&#x6CD5;&#x771F;&#x6B63;&#x6CDB;&#x5316;&#x3002;&#x8FD9;&#x4E5F;&#x662F;&#x4E3A;&#x4EC0;&#x4E48;<strong>&#x53EA;&#x6709;&#x975E;&#x5E38;&#x5927;&#x89C4;&#x6A21;&#x7684;&#x6A21;&#x578B;&#xFF0C;&#x5728;&#x6D77;&#x91CF;&#x6570;&#x636E;&#x8BAD;&#x7EC3;&#x4E0B;&#x624D;&#x80FD;&#x5B9E;&#x73B0;&#x6CDB;&#x5316;</strong>&#x3002;</p><p>&#x8FD9;&#x4E00;&#x70B9;&#x4E5F;&#x9002;&#x7528;&#x4E8E;&#x4EBA;&#x7C7B;&#xFF1A;<strong>&#x5982;&#x679C;&#x4E00;&#x4E2A;&#x4EBA;&#x63A5;&#x53D7;&#x7684;&#x77E5;&#x8BC6;&#x8303;&#x56F4;&#x8FC7;&#x4E8E;&#x72ED;&#x7A84;&#xFF0C;&#x4ED6;&#x4EEC;&#x5F80;&#x5F80;&#x4F1A;&#x8FC7;&#x65E9;&#x5730;&#x5BF9;&#x81EA;&#x5DF1;&#x7684;&#x89C2;&#x70B9;&#x4EA7;&#x751F;&#x6781;&#x7AEF;&#x81EA;&#x4FE1;&#xFF0C;&#x800C;&#x96BE;&#x4EE5;&#x63A5;&#x53D7;&#x65B0;&#x89C2;&#x70B9;</strong>&#x3002;</p><h3 id="6-llm-%E8%83%BD%E5%90%A6%E5%AD%A6%E4%BC%9A%E2%80%9C%E6%80%80%E7%96%91%E2%80%9D%E8%87%AA%E5%B7%B1%EF%BC%9F"><strong>6. LLM &#x80FD;&#x5426;&#x5B66;&#x4F1A;&#x201C;&#x6000;&#x7591;&#x201D;&#x81EA;&#x5DF1;&#xFF1F;</strong></h3><p>&#x771F;&#x6B63;&#x7684;<strong>&#x79D1;&#x5B66;&#x7A81;&#x7834;</strong>&#x5F80;&#x5F80;&#x9700;&#x8981;<strong>&#x8D28;&#x7591;&#x5DF2;&#x6709;&#x77E5;&#x8BC6;&#x4F53;&#x7CFB;</strong>&#x3002;&#x7136;&#x800C;&#xFF0C;&#x5F53;&#x524D; RL &#x8BAD;&#x7EC3;&#xFF08;&#x5982; PPO&#xFF09;&#x5F3A;&#x8C03;<strong>&#x6E10;&#x8FDB;&#x5F0F;&#x53C2;&#x6570;&#x66F4;&#x65B0;</strong>&#xFF0C;&#x9650;&#x5236;&#x4E86;&#x6A21;&#x578B;&#x5BF9;&#x5DF2;&#x6709;&#x77E5;&#x8BC6;&#x7684;&#x5F7B;&#x5E95;&#x63A8;&#x7FFB;&#x3002;</p><p>&#x5728;&#x79D1;&#x5B66;&#x53F2;&#x4E0A;&#xFF0C;<strong>&#x54E5;&#x767D;&#x5C3C;&#x3001;&#x4F3D;&#x5229;&#x7565;&#x3001;&#x725B;&#x987F;</strong>&#x7B49;&#x4EBA;&#x90FD;&#x662F;<strong>&#x8D28;&#x7591;&#x65E7;&#x7406;&#x8BBA;&#x3001;&#x6253;&#x7834;&#x65E2;&#x6709;&#x6846;&#x67B6;</strong>&#xFF0C;&#x624D;&#x5B9E;&#x73B0;&#x4E86;&#x9769;&#x547D;&#x6027;&#x7684;&#x53D1;&#x73B0;&#x3002;&#x4F46; LLM &#x53EA;&#x80FD;<strong>&#x4E0D;&#x65AD;&#x7D2F;&#x79EF;&#x590D;&#x6742;&#x7684;&#x8FD1;&#x4F3C;&#x89C4;&#x5219;</strong>&#xFF0C;&#x800C;&#x65E0;&#x6CD5;&#x4E3B;&#x52A8;&#x63A8;&#x7FFB;&#x9519;&#x8BEF;&#x7684;&#x63A8;&#x7406;&#x65B9;&#x5F0F;&#x3002;&#x8FD9;&#x5C31;&#x50CF;&#x5386;&#x53F2;&#x4E0A;&#x5929;&#x6587;&#x5B66;&#x5BB6;&#x5728;&#x5730;&#x5FC3;&#x8BF4;&#x7684;&#x6846;&#x67B6;&#x4E0B;&#xFF0C;&#x4E0D;&#x65AD;&#x6DFB;&#x52A0;&#x590D;&#x6742;&#x7684;&#x6570;&#x5B66;&#x6A21;&#x578B;&#x6765;&#x89E3;&#x91CA;&#x884C;&#x661F;&#x8F68;&#x9053;&#xFF0C;&#x800C;&#x65E0;&#x6CD5;&#x8F7B;&#x6613;&#x63A5;&#x53D7;&#x65E5;&#x5FC3;&#x8BF4;&#x7684;&#x7B80;&#x5355;&#x7406;&#x8BBA;&#x3002;</p><h3 id="7-llm-%E4%BB%85%E9%9D%A0%E6%95%B0%E5%AD%A6%E6%95%B0%E6%8D%AE%E8%83%BD%E5%AD%A6%E4%BC%9A%E6%95%B0%E5%AD%A6%E5%90%97%EF%BC%9F"><strong>7. LLM &#x4EC5;&#x9760;&#x6570;&#x5B66;&#x6570;&#x636E;&#x80FD;&#x5B66;&#x4F1A;&#x6570;&#x5B66;&#x5417;&#xFF1F;</strong></h3><p>&#x6570;&#x5B66;&#x770B;&#x4F3C;&#x662F;&#x4E00;&#x4E2A;&#x5C01;&#x95ED;&#x4F53;&#x7CFB;&#xFF0C;&#x4F46;&#x4EBA;&#x7C7B;&#x7684;&#x6570;&#x5B66;&#x7406;&#x89E3;<strong>&#x4F9D;&#x8D56;&#x4E8E;&#x73B0;&#x5B9E;&#x7ECF;&#x9A8C;</strong>&#x3002;&#x6BD4;&#x5982; 9+2=11&#xFF0C;&#x7406;&#x89E3;&#x8FD9;&#x4E00;&#x6982;&#x5FF5;&#x9700;&#x8981;&#xFF1A;</p><ul><li>&#x77E5;&#x9053;&#x201C;9&#x201D;&#x548C;&#x201C;2&#x201D;&#x662F;&#x6570;&#x5B57;</li><li>&#x7406;&#x89E3;&#x201C;+&#x201D;&#x8868;&#x793A;&#x52A0;&#x6CD5;</li><li>&#x7406;&#x89E3; 11 &#x662F; 10 &#x4E4B;&#x540E;&#x7684;&#x4E0B;&#x4E00;&#x4E2A;&#x6570;</li><li>&#x8BA4;&#x8BC6;&#x5230; 9+2 = 2+9&#xFF08;&#x4EA4;&#x6362;&#x5F8B;&#xFF09;</li></ul><p>&#x5B69;&#x5B50;&#x5B66;&#x4E60;&#x7B97;&#x672F;&#x65F6;&#x4F1A;&#x7528;&#x624B;&#x6307;&#x6570;&#x6570;&#xFF0C;&#x800C; LLM <strong>&#x6CA1;&#x6709;&#x8FD9;&#x6837;&#x7684;&#x73B0;&#x5B9E;&#x7ECF;&#x9A8C;</strong>&#x3002;&#x5B83;&#x5FC5;&#x987B;<strong>&#x4F9D;&#x9760;&#x5B8C;&#x5168;&#x4E0D;&#x540C;&#x7684;&#x65B9;&#x5F0F;&#x6765;&#x5B66;&#x4E60;&#x7B97;&#x672F;</strong>&#xFF0C;&#x8FD9;&#x53EF;&#x80FD;&#x6C38;&#x8FDC;&#x65E0;&#x6CD5;&#x4E0E;&#x4EBA;&#x7C7B;&#x7684;&#x65B9;&#x5F0F;&#x5BF9;&#x9F50;&#x3002;</p><hr><h2 id="%E7%BB%93%E8%AE%BA%EF%BC%9Allm-%E4%BB%8D%E7%84%B6%E6%98%AF%E4%B8%80%E4%B8%AA%E4%B8%8D%E7%A1%AE%E5%AE%9A%E7%9A%84%E9%BB%91%E7%AE%B1"><strong>&#x7ED3;&#x8BBA;&#xFF1A;LLM &#x4ECD;&#x7136;&#x662F;&#x4E00;&#x4E2A;&#x4E0D;&#x786E;&#x5B9A;&#x7684;&#x9ED1;&#x7BB1;</strong></h2><p>&#x6211;&#x7684;&#x5B9E;&#x9A8C;&#x8868;&#x660E;&#xFF0C;<strong>&#x65E0;&#x8BBA;&#x6A21;&#x578B;&#x5927;&#x5C0F;&#xFF0C;&#x5F53;&#x524D; LLM &#x67B6;&#x6784;&#x90FD;&#x65E0;&#x6CD5;&#x771F;&#x6B63;&#x5B66;&#x4F1A;&#x7B97;&#x672F;&#x89C4;&#x5219;</strong>&#x3002;&#x5B83;&#x4EEC;&#x53EA;&#x80FD;&#x901A;&#x8FC7;<strong>&#x672A;&#x77E5;&#x7684;&#x8FD1;&#x4F3C;&#x65B9;&#x6CD5;</strong>&#x8FDB;&#x884C;&#x8BA1;&#x7B97;&#xFF0C;&#x800C;&#x8FD9;&#x79CD;&#x65B9;&#x6CD5;&#x7684;&#x51C6;&#x786E;&#x6027;&#x65E0;&#x6CD5;&#x4FDD;&#x8BC1;&#x3002;</p><p>&#x5982;&#x679C;&#x6211;&#x4EEC;&#x9700;&#x8981;<strong>&#x7EDD;&#x5BF9;&#x6B63;&#x786E;&#x7684;&#x7B97;&#x672F;&#x8BA1;&#x7B97;</strong>&#xFF0C;&#x6700;&#x597D;&#x7684;&#x89E3;&#x51B3;&#x65B9;&#x6848;&#x5E76;&#x4E0D;&#x662F; LLM&#xFF0C;&#x800C;&#x662F;&#x4E00;&#x4E2A;<strong>&#x6309;&#x7167;&#x4EBA;&#x7C7B;&#x5B9A;&#x4E49;&#x7684;&#x6570;&#x5B66;&#x89C4;&#x5219;&#x7F16;&#x5199;&#x7684;&#x8BA1;&#x7B97;&#x5668;</strong>&#x3002;</p><p></p><h2 id="%E4%BB%A3%E7%A0%81"><a href="https://github.com/optman/nanoGPT-rs/tree/arithmetic">&#x4EE3;&#x7801;</a></h2>]]></content:encoded></item><item><title><![CDATA[Can LLMs Really Learn Arithmetic?]]></title><description><![CDATA[<h3></h3><p>Inspired by the success of DeepSeek R1&#x2019;s RL training, I set out to revisit reinforcement learning (RL) techniques. I was deeply fascinated by RL four years ago when AlphaGo defeated human champions. Although OpenAI has applied RL, particularly RLHF, in training ChatGPT, I never fully understood how RL</p>]]></description><link>https://blog.optman.net/can-llms-really-learn-arithmetic/</link><guid isPermaLink="false">67dbf5ae8fb95700011682bc</guid><category><![CDATA[AI]]></category><category><![CDATA[LLM]]></category><dc:creator><![CDATA[optman]]></dc:creator><pubDate>Thu, 20 Mar 2025 13:17:25 GMT</pubDate><content:encoded><![CDATA[<h3></h3><p>Inspired by the success of DeepSeek R1&#x2019;s RL training, I set out to revisit reinforcement learning (RL) techniques. I was deeply fascinated by RL four years ago when AlphaGo defeated human champions. Although OpenAI has applied RL, particularly RLHF, in training ChatGPT, I never fully understood how RL could be effectively integrated into LLM training.</p><p><a href="https://blog.optman.net/donkeycar-rl/">A few years ago</a>, I attempted RL training on a Raspberry Pi-based DonkeyCar, but with limited success. That experience gave me a glimpse of RL&#x2019;s potential, as well as its limitations. However, after reading DeepSeek&#x2019;s papers, I was impressed by their novel GRPO (Group Relative Policy Optimization), which eliminates the need for value models, greatly simplifying RL-based optimization. I then explored GRPO implementations from <a href="https://github.com/huggingface/trl">huggingface/trl</a> and repositories like TinyZero. While the core algorithm is relatively simple, the surrounding scaffolding code can be quite tedious. As a scientist once said, &quot;To truly understand the world, you must build it yourself.&quot;</p><h3 id="replicating-grpo-with-nanogpt-rs">Replicating GRPO with nanoGPT-rs</h3><p>Motivated by this principle, I decided to replicate GRPO myself, building it upon <a href="https://github.com/optman/nanogpt-rs">nanoGPT-rs</a>, a Rust-based replica of <a href="https://github.com/karpathy/nanoGPT">nanoGPT</a> that I created two years ago. By implementing LLMs from scratch, I aim to gain a deeper understanding of transformer architectures.</p><p>I appreciate <strong><a href="https://github.com/coreylowman/dfdx">dfdx</a></strong>, a Rust-based machine learning framework similar to PyTorch, for its ability to statically check tensor shapes at compile time. This enforces correctness and improves comprehension of neural network components. Unfortunately, dfdx development has slowed, but its approach to type safety remains valuable.</p><h3 id="the-challenge-of-arithmetic-in-llms">The Challenge of Arithmetic in LLMs</h3><p>My goal is to train an LLM to perform simple <strong>addition</strong>. At first glance, this might seem trivial, but even the most advanced models, like GPT-4, occasionally struggle with arithmetic. The key question is: <strong>Do LLMs actually learn arithmetic rules, or do they merely memorize patterns from training data?</strong></p><p>To simplify the task, I train the model exclusively on arithmetic expressions, avoiding other textual data. My dataset consists of:</p><ul><li><strong>Two 1-digit numbers:</strong> e.g., <code>2+1=3</code></li><li><strong>Two 2-digit numbers:</strong> e.g., <code>11+12=23</code></li><li><strong>Three 1-digit numbers with an intermediate step:</strong> e.g., <code>1+1+1=2+1=3</code></li></ul><p>The model is trained with prompts like:</p><pre><code>2+1=  
11+12=  
1+1+1=  
</code></pre><h3 id="findings-approximation-vs-true-learning">Findings: Approximation vs. True Learning</h3><p>I found that a <strong>pre-trained model fine-tuned on arithmetic data</strong> can achieve high accuracy within a few epochs, given a sufficiently large training set. However, after a certain point, performance plateaus. Further improvements can be achieved through RL methods, but even at near 100% accuracy, the model often <strong>fails to generalize to unseen samples</strong>.</p><p>This suggests that the model <strong>does not truly learn arithmetic as humans do</strong>. Instead, it applies some form of approximation, which is fundamentally different from human logical deduction.</p><hr><h2 id="what-i-have-learned">What I Have Learned</h2><h3 id="1-llms-won%E2%80%99t-magically-learn-arithmetic-rules">1. LLMs Won&#x2019;t Magically Learn Arithmetic Rules</h3><p>LLMs do not inherently learn arithmetic rules. While they approximate addition in some way, their method is not necessarily aligned with the rules we use. As a result, their answers are <strong>not guaranteed to be 100% correct or predictable</strong>.</p><h3 id="2-overfitting-is-a-common-pitfall">2. Overfitting Is a Common Pitfall</h3><p>For simple arithmetic tasks, LLMs tend to overfit the training data. This means that <strong>a smaller model is often sufficient</strong>, as it is less likely to memorize specific results and instead forced to generalize patterns. RL training can help mitigate overfitting by encouraging the model to <strong>learn underlying rules</strong> rather than just memorizing data.</p><h3 id="3-rl-training-requires-extensive-trial-and-error">3. RL Training Requires Extensive Trial and Error</h3><p>RL training relies on <strong>randomly stumbling upon the correct answer</strong> and refining the model through repeated trials. This makes it highly inefficient compared to pre-training, which can achieve a reasonable level of accuracy in fewer epochs. However, given sufficient training time, RL can ultimately lead to <strong>higher accuracy and better generalization</strong> than pure pre-training.</p><h3 id="4-the-best-approach-pre-training-followed-by-rl">4. The Best Approach: Pre-Training Followed by RL</h3><p>A more effective strategy is to <strong>first pre-train the model</strong> and then fine-tune it with RL.</p><ul><li><strong>Pre-training</strong> helps the model learn fundamental rules, such as recognizing that outputs should be numbers. This <strong>reduces the search space</strong> during RL training and speeds up convergence.</li><li>However, <strong>excessive pre-training can lead to overfitting</strong>, constraining the model&#x2019;s ability to explore new solutions during RL. If the model learns incorrect arithmetic rules early on, it becomes difficult to unlearn them later due to the <strong>local gradient descent nature</strong> of neural network training, which can trap the model in a local optimum.</li></ul><h3 id="5-data-diversity-is-critical-for-generalization">5. Data Diversity Is Critical for Generalization</h3><p>A well-diversified training dataset <strong>prevents overfitting</strong>. The <strong>larger the model</strong>, the more diverse data it requires. If a model becomes <strong>too confident too early</strong>, it stops exploring and fails to generalize.</p><p>The ideal <strong>learning curve</strong> should have a <strong>sudden rise in accuracy after a long period of exploration</strong>. If accuracy increases <strong>linearly and consistently</strong>, it indicates that the model is overfitting rather than generalizing. This might explain why <strong>only very large models trained on massive datasets achieve true generalization</strong>.</p><p>The same principle applies to humans: if a person is exposed only to a narrow set of knowledge, they may become overly confident in their ideas too soon and struggle to adapt to new perspectives.</p><h3 id="6-can-an-llm-build-doubt">6. Can an LLM Build Doubt?</h3><p>For a model to <strong>truly discover new rules</strong>, it needs to experience <strong>doubt and skepticism</strong>&#x2014;a necessary precursor to paradigm shifts. However, current RL methods, such as PPO, emphasize <strong>gradual parameter updates</strong>, discouraging drastic changes.</p><p>Historically, scientists like <strong>Copernicus, Galileo, and Newton</strong> made groundbreaking discoveries by rejecting overly complex models that fit existing theories but lacked true explanatory power. Before the heliocentric model, astronomers kept adding epicycles to explain planetary motion within a geocentric framework. LLMs, in their current form, behave similarly: instead of discarding flawed approximations, they <strong>layer on increasingly complex approximations</strong>.</p><p>Can an LLM independently <strong>challenge its own learned framework</strong> and arrive at a drastically simpler, more correct solution? <strong>I don&#x2019;t think so.</strong> Unlike humans, LLMs lack the ability to discard previous assumptions and make radical leaps in understanding.</p><h3 id="7-can-an-llm-learn-math-purely-from-mathematical-data">7. Can an LLM Learn Math Purely from Mathematical Data?</h3><p>Mathematics may seem self-contained, but human learning relies on <strong>external knowledge and experience</strong>. Even basic arithmetic, such as <strong>9 + 2 = 11</strong>, requires understanding concepts like:</p><ul><li>What numbers represent</li><li>The meaning of addition</li><li>The structure of the decimal system</li><li>The <strong>commutative property</strong> (e.g., 9 + 2 is the same as 2 + 9)</li></ul><p>Children often learn arithmetic using <strong>physical interactions</strong>, such as counting on fingers. Without such real-world context, how does an LLM develop number sense? It must <strong>devise an entirely alien method</strong> for solving math problems&#x2014;one that may never fully align with human reasoning. This raises doubts about whether an LLM can ever truly <strong>internalize</strong> arithmetic the way humans do.</p><hr><h3 id="comparing-my-approach-to-previous-research">Comparing My Approach to Previous Research</h3><p>Two years ago, <a href="https://arxiv.org/abs/2307.03381">another study</a> attempted to teach arithmetic using n<strong>anoGPT</strong>, but they relied purely on pre-training. Their conclusion was that <strong>data formatting is crucial</strong>&#x2014;plain-text representations (like my dataset) were inefficient, especially when learning <strong>carry operations</strong> in addition. They found that <strong>explicit reasoning steps</strong> (similar to how teachers explain math) significantly improved learning.</p><p>However, <strong>my goal is different</strong>. Instead of explicitly guiding the model like a teacher, I wanted to see if <strong>LLMs can independently discover arithmetic rules</strong> purely through pattern observation and trial-and-error learning.</p><p><strong>So far, the answer is no.</strong></p><h3 id="conclusion-llms-will-always-be-an-approximation">Conclusion: LLMs Will Always Be an Approximation</h3><p>Based on my findings, I don&#x2019;t believe LLMs&#x2014;whether small or large&#x2014;can ever <strong>truly</strong> learn arithmetic in the way humans do, at least with their current architectures. They <strong>approximate</strong> results in ways we don&#x2019;t fully understand, making them inherently unreliable for arithmetic.</p><p>If we need <strong>guaranteed correctness</strong>, the best solution isn&#x2019;t an LLM&#x2014;it&#x2019;s a <strong>calculator</strong>, explicitly programmed to follow well-defined arithmetic rules.</p><p><a href="https://github.com/optman/nanoGPT-rs/tree/arithmetic"><strong>Code</strong></a></p>]]></content:encoded></item><item><title><![CDATA[Understanding Rust's Array Conversion: When Copying Isn't Really Copying]]></title><description><![CDATA[<p>When converting slices to fixed-size arrays in Rust, there&apos;s an interesting interplay between language semantics and compiler optimizations. Let&apos;s dive into a common pattern and understand what&apos;s actually happening under the hood.</p><h2 id="the-code-in-question">The Code in Question</h2><pre><code class="language-rust">fn ipv4_from_slice(s: &amp;[u8]) -&</code></pre>]]></description><link>https://blog.optman.net/understanding-rusts-array-conversion-when-copying-isnt-really-copying/</link><guid isPermaLink="false">6787b9a38fb95700011682ab</guid><category><![CDATA[rust]]></category><dc:creator><![CDATA[optman]]></dc:creator><pubDate>Wed, 15 Jan 2025 13:36:41 GMT</pubDate><content:encoded><![CDATA[<p>When converting slices to fixed-size arrays in Rust, there&apos;s an interesting interplay between language semantics and compiler optimizations. Let&apos;s dive into a common pattern and understand what&apos;s actually happening under the hood.</p><h2 id="the-code-in-question">The Code in Question</h2><pre><code class="language-rust">fn ipv4_from_slice(s: &amp;[u8]) -&gt; IpAddr {
    let addr: [u8; 4] = s[..4].try_into().expect(&quot;Slice with incorrect length&quot;);
    addr.into()
}
</code></pre><h2 id="language-semantics-vs-runtime-reality">Language Semantics vs. Runtime Reality</h2><p>At first glance, this code appears to:</p><ol><li>Allocate a new 4-byte array on the stack (<code>addr</code>)</li><li>Copy data from the slice into this array (via <code>try_into()</code>)</li><li>Convert the array into an <code>IpAddr</code></li></ol><p>But is that what really happens at runtime? Not quite!</p><h2 id="understanding-tryinto">Understanding <code>try_into()</code></h2><p>Let&apos;s look at the actual implementation of <code>try_into()</code> for slices:</p><pre><code class="language-rust">impl&lt;T, const N: usize&gt; TryFrom&lt;&amp;[T]&gt; for [T; N]
where
    T: Copy,
{
    type Error = TryFromSliceError;

    fn try_from(slice: &amp;[T]) -&gt; Result&lt;[T; N], TryFromSliceError&gt; {
        if slice.len() == N {
            // SAFETY: We just checked that the slice has the correct length
            Ok(unsafe { *(slice.as_ptr() as *const [T; N]) })
        } else {
            Err(TryFromSliceError(()))
        }
    }
}
</code></pre><p>The magic happens in that unsafe block. Instead of copying data, it:</p><ol><li>Checks if the slice length matches the array length</li><li>If it matches, reinterprets the slice&apos;s memory as an array through a pointer cast</li><li>No actual memory copying occurs!</li></ol><h2 id="the-stack-allocation-that-isnt">The Stack Allocation That Isn&apos;t</h2><p>When we write:</p><pre><code class="language-rust">let addr: [u8; 4] = ...
</code></pre><p>From the language&apos;s perspective, this declares a new array that should be allocated on the stack. However, modern compilers are incredibly smart about optimizations. They can see that:</p><ol><li>We&apos;re just reinterpreting existing memory (via <code>try_into()</code>)</li><li>The original data&apos;s lifetime covers our needs</li><li>No actual mutation of the data occurs</li></ol><p>Therefore, the compiler can optimize away the stack allocation entirely. The final machine code might just work directly with the original memory location.</p><h2 id="why-write-it-this-way-then">Why Write It This Way Then?</h2><p>If the compiler optimizes away our explicit array, why not just use references? There are several good reasons:</p><ol><li><strong>Type Safety</strong>: The array type <code>[u8; 4]</code> explicitly states our requirements</li><li><strong>Ownership Clarity</strong>: We&apos;re making it clear we want to own this data</li><li><strong>Zero-Cost Abstraction</strong>: We get the safety of Rust&apos;s type system with the performance of optimized code</li><li><strong>Maintainability</strong>: The code clearly expresses our intent while letting the compiler handle the optimization</li></ol><h2 id="the-power-of-zero-cost-abstractions">The Power of Zero-Cost Abstractions</h2><p>This is a perfect example of Rust&apos;s zero-cost abstractions principle. We write code that&apos;s:</p><ul><li>Clear about its intentions</li><li>Type-safe</li><li>Semantically correct</li><li>Easy to understand</li></ul><p>While the compiler ensures it runs with:</p><ul><li>No unnecessary copies</li><li>No unnecessary allocations</li><li>Maximum efficiency</li></ul><h2 id="conclusion">Conclusion</h2><p>What looks like a memory allocation and copy operation in Rust source code often compiles down to much more efficient operations. This is the beauty of Rust&apos;s design: it allows us to write safe, clear code while the compiler handles the heavy lifting of optimization.</p><p>The next time you see a slice-to-array conversion in Rust, remember that what you&apos;re seeing in the source code isn&apos;t necessarily what&apos;s happening in the final binary. The compiler is working hard behind the scenes to make your code both safe and fast.</p><hr><p>&#x2728; This blog was written by AI! &#x1F916;</p><hr>]]></content:encoded></item><item><title><![CDATA[Understanding Slices in Rust: A Deep Dive into &data[start..end]]]></title><description><![CDATA[<p>Rust is a systems programming language that emphasizes safety and performance, often requiring a deeper understanding of memory management and ownership concepts. One common feature in Rust is the ability to create slices, which provide a view into a contiguous sequence of elements. In this blog post, we will explore</p>]]></description><link>https://blog.optman.net/understanding-slices-in-rust/</link><guid isPermaLink="false">6780c0328fb9570001168290</guid><category><![CDATA[rust]]></category><dc:creator><![CDATA[optman]]></dc:creator><pubDate>Fri, 10 Jan 2025 06:39:10 GMT</pubDate><content:encoded><![CDATA[<p>Rust is a systems programming language that emphasizes safety and performance, often requiring a deeper understanding of memory management and ownership concepts. One common feature in Rust is the ability to create slices, which provide a view into a contiguous sequence of elements. In this blog post, we will explore the line of code:</p><pre><code class="language-rust">let slice = &amp;data[start..end];
</code></pre><h3 id="breakdown-of-the-code">Breakdown of the Code</h3><p>In this line, we are creating a slice from a collection called <code>data</code>. Let&apos;s analyze the components of this code:</p><ol><li><strong><code>data</code></strong>: This is an array, vector, or any collection that supports indexing.</li><li><strong><code>start..end</code></strong>: This syntax indicates a range. It defines the indices of the elements you want to include in the slice, starting from <code>start</code> and ending just before <code>end</code>.</li><li><strong><code>&amp;</code></strong>: This operator creates a reference to the slice.</li></ol><h3 id="what-is-tstartend">What is <code>T[start..end]</code>?</h3><p>When you write <code>data[start..end]</code>, you are using Rust&apos;s slicing syntax. The expression <code>data[start..end]</code> does not create a new slice or allocate new memory; instead, it generates a <em>logical view</em> of the data between the specified indices.</p><ul><li><strong>Type of <code>T[start..end]</code></strong>: The type returned by this expression is a slice type, denoted as <code>[T]</code>. This type represents a contiguous sequence of elements of type <code>T</code>, but it is a <em>dynamically sized type</em> (DST). This means that the size of the slice is not known at compile time; it can vary based on the range specified.</li></ul><h3 id="difference-between-t-and-t">Difference Between <code>[T]</code> and <code>&amp;[T]</code></h3><p><strong><code>[T]</code></strong>:</p><ul><li>This represents a slice type, but it is a dynamically sized type (DST). You cannot store this type directly in a variable because Rust needs to know the size of types at compile time.</li><li>It acts like a view into a sequence of elements, but it does not carry ownership or a fixed size.</li></ul><p><strong><code>&amp;[T]</code></strong>:</p><ul><li>This is a reference to a slice. The <code>&amp;</code> operator indicates that it is borrowing the slice, which consists of a pointer to the first element and a length.</li><li>This type is fixed in size and can be stored in a variable. It allows you to safely access the data without taking ownership.</li></ul><h3 id="the-necessity-of-slices-as-logical-views">The Necessity of <code>&amp;</code>: Slices as Logical Views</h3><p>The use of <code>&amp;</code> is crucial when working with slices in Rust. Here&#x2019;s why:</p><p><strong>Logical View</strong>: A slice represents a logical view of the underlying data. It does not own the data it points to; it merely describes how to access a portion of an array or vector. Because of this, slices must always be accessed by reference.</p><p><strong>Memory Safety</strong>: By requiring references for slices, Rust ensures that the original data remains valid for as long as the slice is used. This prevents issues like dangling pointers, where a reference points to data that has been deallocated or gone out of scope.</p><p><strong>Lifetime Management</strong>: Using references allows Rust&apos;s borrow checker to enforce rules about how long a slice can live, which is essential for maintaining memory safety without garbage collection.</p><h3 id="conclusion">Conclusion</h3><p>The line of code <code>let slice = &amp;data[start..end];</code> encapsulates several important concepts in Rust: slices as logical views, the distinction between <code>[T]</code> and <code>&amp;[T]</code>, and the necessity of using references. Understanding these concepts is fundamental to mastering Rust&apos;s memory management and ownership model.</p><p>By grasping how slices work and why they are accessed through references, you can write safer and more efficient Rust code. Slices provide a powerful way to work with data without unnecessary copying, while maintaining the language&apos;s guarantees of safety and concurrency. </p><p></p><hr><p>&#x2728; This blog was written by AI! &#x1F916;</p><hr>]]></content:encoded></item><item><title><![CDATA[Understanding Rust's Trait Objects: The Tale of Two References]]></title><description><![CDATA[<p>When working with Rust&apos;s trait objects, you might encounter an interesting difference in behavior between <code>&amp;dyn Trait</code> and <code>Box&lt;dyn Trait&gt;</code>. Let&apos;s explore this subtle but important distinction that reveals much about Rust&apos;s type system and safety principles.</p><h2 id="a-tale-of-two-references">A Tale of</h2>]]></description><link>https://blog.optman.net/understanding-rusts-trait-objects-the-tale-of-two-references/</link><guid isPermaLink="false">677e71028fb9570001168283</guid><dc:creator><![CDATA[optman]]></dc:creator><pubDate>Wed, 08 Jan 2025 12:37:02 GMT</pubDate><content:encoded><![CDATA[<p>When working with Rust&apos;s trait objects, you might encounter an interesting difference in behavior between <code>&amp;dyn Trait</code> and <code>Box&lt;dyn Trait&gt;</code>. Let&apos;s explore this subtle but important distinction that reveals much about Rust&apos;s type system and safety principles.</p><h2 id="a-tale-of-two-references">A Tale of Two References</h2><p>Let&apos;s start with a simple example that demonstrates this difference:</p><pre><code class="language-rust">trait A {
    fn do_something(&amp;self);
}

trait B {
    fn do_something_else(&amp;self);
}

// Implementing B for both reference types
impl B for &amp;dyn A {
    fn do_something_else(&amp;self) {
        self.do_something();
        println!(&quot;Doing something else!&quot;);
    }
}

impl B for Box&lt;dyn A&gt; {
    fn do_something_else(&amp;self) {
        self.do_something();
        println!(&quot;Doing something else!&quot;);
    }
}

struct Concrete;

impl A for Concrete {
    fn do_something(&amp;self) {
        println!(&quot;Concrete does something!&quot;);
    }
}

fn main() {
    let concrete = Concrete;
    
    // Case 1: &amp;dyn A
    let a_ref: &amp;dyn A = &amp;concrete;
    a_ref.do_something_else();  // This works
    // let b_ref: &amp;dyn B = a_ref;  // This fails!
    
    // Case 2: Box&lt;dyn A&gt;
    let a_box: Box&lt;dyn A&gt; = Box::new(concrete);
    a_box.do_something_else();  // This works
    let b_ref: &amp;dyn B = &amp;a_box; // This also works!
}
</code></pre><h2 id="the-key-difference">The Key Difference</h2><p>The fascinating part is that while both types can call methods directly, they behave differently when it comes to creating new trait object references:</p><ol><li>With <code>&amp;dyn A</code>, you cannot create a new trait object reference <code>&amp;dyn B</code>, even though <code>&amp;dyn A</code> implements <code>B</code>.</li><li>With <code>Box&lt;dyn A&gt;</code>, you can freely create a new trait object reference <code>&amp;dyn B</code>.</li></ol><h2 id="why-this-happens">Why This Happens</h2><p>The explanation boils down to two fundamental aspects of Rust&apos;s type system:</p><h3 id="1-reference-coercion-rules">1. Reference Coercion Rules</h3><p><code>&amp;dyn A</code> is already a borrowed reference (a fat pointer containing a data pointer and vtable). Rust intentionally prevents coercing one kind of reference into another, even when it might be technically safe. This is part of Rust&apos;s conservative approach to type safety.</p><h3 id="2-concrete-types-vs-references">2. Concrete Types vs References</h3><p><code>Box&lt;dyn A&gt;</code> is a concrete type, not a reference. When you have a concrete type that implements a trait, Rust allows you to create any kind of trait object reference to it. This is similar to how you can create multiple different trait object references to any concrete type that implements multiple traits.</p><h2 id="code-examples-in-practice">Code Examples in Practice</h2><p>Here&apos;s how this distinction plays out in practical code:</p><pre><code class="language-rust">// Working with concrete types - both ways work
let concrete = Concrete;
let a_ref: &amp;dyn A = &amp;concrete;
let b_ref: &amp;dyn B = &amp;concrete;  // Works fine

// Working with trait objects
let a_trait: &amp;dyn A = &amp;concrete;
// let b_trait: &amp;dyn B = a_trait;  // Fails! Can&apos;t coerce references

// Working with Box
let boxed: Box&lt;dyn A&gt; = Box::new(concrete);
let b_trait: &amp;dyn B = &amp;boxed;  // Works fine!
</code></pre><h2 id="best-practices-and-implications">Best Practices and Implications</h2><p>This behavior leads to some practical guidelines:</p><p>If you need to view a type through multiple trait objects, either:</p><ul><li>Use the concrete type and create references as needed</li><li>Use <code>Box&lt;dyn Trait&gt;</code> when you need owned trait objects</li><li>Avoid trying to convert between different trait object references</li></ul><p>When designing APIs:</p><ul><li>Consider using <code>Box&lt;dyn Trait&gt;</code> if clients need to view the object through multiple traits</li><li>Use <code>&amp;dyn Trait</code> when you only need a single trait view and want to avoid allocation</li></ul><h2 id="conclusion">Conclusion</h2><p>This distinction between <code>&amp;dyn Trait</code> and <code>Box&lt;dyn Trait&gt;</code> perfectly exemplifies Rust&apos;s philosophy:</p><ol><li>Safety First: Rust prevents reference coercion between trait objects to maintain its safety guarantees.</li><li>Explicit over Implicit: When you need to view an object through multiple traits, Rust prefers explicit handling through concrete types.</li><li>Zero-Cost Abstractions: Both mechanisms provide dynamic dispatch while maintaining different safety and usage characteristics.</li></ol><p>Understanding these differences helps write more idiomatic Rust code and make better decisions about trait object usage in your APIs.</p><p>Remember: when you need flexibility in trait object conversions, reach for <code>Box&lt;dyn Trait&gt;</code>. When you just need a simple borrowed view of a trait, <code>&amp;dyn Trait</code> is your friend. Each has its place in Rust&apos;s rich type system.</p><p></p><hr><p>&#x2728; This blog was written by AI! &#x1F916;</p><hr>]]></content:encoded></item><item><title><![CDATA[Understanding Trait Objects and Trait-to-Trait Relationships in Rust]]></title><description><![CDATA[<p>During a recent coding session, I encountered an interesting problem that led us to explore the depths of Rust&apos;s trait system. The journey revealed some important distinctions between Rust&apos;s approach and traditional OOP inheritance.</p><h2 id="the-initial-problem">The Initial Problem</h2><p>I started with code that attempted to convert between</p>]]></description><link>https://blog.optman.net/understanding-trait-objects-and-trait-to-trait-relationships-in-rust/</link><guid isPermaLink="false">677d22078fb9570001168260</guid><category><![CDATA[rust]]></category><dc:creator><![CDATA[optman]]></dc:creator><pubDate>Tue, 07 Jan 2025 12:51:29 GMT</pubDate><content:encoded><![CDATA[<p>During a recent coding session, I encountered an interesting problem that led us to explore the depths of Rust&apos;s trait system. The journey revealed some important distinctions between Rust&apos;s approach and traditional OOP inheritance.</p><h2 id="the-initial-problem">The Initial Problem</h2><p>I started with code that attempted to convert between two trait objects:</p><pre><code class="language-rust">trait Cryptor {
    // Cryptor-specific methods
}

trait Finalizer {
    // Finalizer-specific methods
}

impl Finalizer for dyn Cryptor {}  // Implementing Finalizer for Cryptor trait object

// Attempting to convert &amp;dyn Cryptor to &amp;dyn Finalizer
pub fn cryptor(mut self, cryptor: &amp;dyn Cryptor) -&gt; Result&lt;Self&gt; {
    self.finalizer.add(cryptor as &amp;dyn Finalizer);  // This failed!
    Ok(self)
}
</code></pre><p>This code failed with the error:</p><pre><code>error[E0605]: non-primitive cast: `&amp;dyn Cryptor` as `&amp;dyn Finalizer`
</code></pre><h2 id="the-journey-of-understanding">The Journey of Understanding</h2><h3 id="second-attempt-boxdyn-trait">Second Attempt: <code>Box&lt;dyn Trait&gt;</code></h3><p>I then discovered that using <code>Box&lt;dyn Trait&gt;</code> made things work:</p><pre><code class="language-rust">impl Finalizer for Box&lt;dyn Cryptor&gt; {}

pub fn cryptor(mut self, cryptor: &amp;Box&lt;dyn Cryptor&gt;) -&gt; Result&lt;Self&gt; {
    self.finalizer.add(cryptor);
    Ok(self)
}

impl Finalizer for Box&lt;dyn Cryptor&gt;{}
</code></pre><p>This worked, but why?</p><h2 id="the-key-insights">The Key Insights</h2><h3 id="trait-for-trait-implementation-reality">Trait-for-Trait Implementation Reality</h3><p>When we write:</p><pre><code class="language-rust">trait A {}
trait B {}
impl B for dyn A {}
</code></pre><p>What this actually does is automatically implement trait B for any concrete type that implements trait A. It does NOT create a conversion path between trait objects.</p><h3 id="trait-objects-and-type-erasure">Trait Objects and Type Erasure</h3><p>A trait object (<code>dyn Trait</code>) erases the concrete type information, keeping only the vtable for that specific trait&apos;s methods. Even if the original type implemented multiple traits, that information is lost in the trait object.</p><h3 id="rust-traits-vs-oop-inheritance">Rust Traits vs OOP Inheritance</h3><p>Unlike C++ or Java where inheritance creates an &quot;is-a&quot; relationship allowing upcasting, Rust&apos;s trait bounds work differently. When we write <code>TraitB: TraitA</code>, we&apos;re saying &quot;to implement TraitB, you must also implement TraitA&quot; - it&apos;s a constraint, not an inheritance relationship.</p><h3 id="why-boxdyn-trait-works">Why <code>Box&lt;dyn Trait&gt;</code> Works</h3><p>The <code>Box&lt;dyn Trait&gt;</code> approach works because we&apos;re implementing <code>Finalizer</code> for a concrete sized type (<code>Box&lt;dyn Cryptor&gt;</code>), not trying to convert between trait objects directly.</p><h2 id="lessons-learned">Lessons Learned</h2><ol><li>Trait objects are fundamentally different from inheritance-based polymorphism in other languages.</li><li>Implementing a trait for another trait (<code>impl TraitB for dyn TraitA</code>) creates a blanket implementation for concrete types, not a conversion path between trait objects.</li><li>When working with trait objects, we need to be mindful of type erasure and the limitations it imposes.</li><li>Using <code>Box&lt;dyn Trait&gt;</code> can provide a way to work with trait objects when direct trait-to-trait conversion isn&apos;t possible.</li></ol><p>This exploration highlighted the unique aspects of Rust&apos;s trait system and how it differs from traditional OOP inheritance. Understanding these differences is crucial for writing idiomatic and effective Rust code.</p><p></p><hr><p>&#x2728; This blog was written by AI! &#x1F916;</p><hr>]]></content:encoded></item><item><title><![CDATA[Mounting a Host Directory with Write Access in an LXC Container: A Journey]]></title><description><![CDATA[<p><strong>Introduction</strong></p><p>I recently set up a BitTorrent download service on my Raspberry Pi using an LXC (Linux Containers) container. While LXC containers are convenient for isolating applications and managing resources, I encountered a challenge when attempting to mount a host directory with write access inside the container. Persistent storage and</p>]]></description><link>https://blog.optman.net/mounting-a-host-directory-with-write-access-in-an-lxc-container-a-journey/</link><guid isPermaLink="false">670a1a8c8eb62400015d3b99</guid><dc:creator><![CDATA[optman]]></dc:creator><pubDate>Sat, 12 Oct 2024 06:44:19 GMT</pubDate><content:encoded><![CDATA[<p><strong>Introduction</strong></p><p>I recently set up a BitTorrent download service on my Raspberry Pi using an LXC (Linux Containers) container. While LXC containers are convenient for isolating applications and managing resources, I encountered a challenge when attempting to mount a host directory with write access inside the container. Persistent storage and data sharing between the host and container are essential for applications like BitTorrent, which require writing and reading files from a shared location.</p><p><strong>Initial Attempts</strong></p><p>Initially, I thought attaching a host directory to the container would be a straightforward process using the <code>lxc config device add</code> command. However, when trying to access the mounted directory from within the container, I encountered permission denied errors, preventing me from writing or modifying files.</p><p><strong>Understanding the Problem</strong></p><p>After failed attempts and research, I realized that the root cause of the issue was the user and group ID mapping between the host and container environments. For security reasons, LXC containers run with different user and group IDs than the host system. The user IDs inside the container are mapped to a specific range of user IDs on the host. For example, the root user (UID=0) in the container might be mapped to UID=100000 on the host, and UID=1 in the container could be mapped to UID=100001 on the host.</p><p>Unless a host directory is configured with permissive permissions (e.g., mode 777, allowing all users full control), a container would not be able to access or modify files within that directory. However, setting broad permissions is generally not recommended for security reasons.</p><p><strong>Failed Solutions</strong></p><p>Initially, I tried various solutions suggested by ChatGPT, Claude, and other online resources. These solutions often involved using the <code>idmap</code> technique to force a mapping between a specific container user and a designated host user within the container configuration. For example:</p><pre><code>lxc config set &lt;container-name&gt; raw.idmap &quot;both 1001 1001&quot;
</code></pre><p>However, for unknown reasons (possibly related to the Raspbian kernel configuration), my container failed to boot after setting the <code>idmap</code> configuration. Additionally, the values in <code>/etc/subuid</code> and <code>/etc/subgid</code> (which should control the user and group ID mapping ranges) did not seem to be respected by the system.</p><p><strong>My Solution</strong></p><p>After investigating further, I discovered that the root user (UID=0) inside my containers was being mapped to UID=1000000 on the host system. Instead of relying on the <code>idmap</code> configuration, I decided to create a new user (<code>bt</code>) inside the container and set the permissions on the host directory explicitly for the mapped UID and GID of the <code>bt</code> user.</p><p>Here are the steps I followed:</p><p><strong>Create the <code>bt</code> user in the container</strong>:</p><pre><code>groupadd -g 1001 bt
adduser bt -u 1001 -g 1001
</code></pre><p><strong>Set permissions on the host directory for the <code>bt</code> user</strong>:</p><pre><code>sudo chown 1001001:1001001 /path/to/host/directory
sudo chmod 770 /path/to/host/directory
</code></pre><p><strong>Map the new user/group IDs to the corresponding IDs within the container</strong>:<br>Since the root user (UID=0) inside the container was mapped to UID=1000000 on the host, and the new user <code>bt</code> (UID=1001) inside the container would be mapped to UID=1001001 on the host, no further mapping configuration was needed.</p><p><strong>Run the BitTorrent service as the new user inside the container</strong>:<br>Within the container, I ran the BitTorrent service as the new user <code>bt</code>, and now it had write access to the mounted host directory.</p><p><strong>Security Considerations</strong></p><p>By running the BitTorrent service as a non-root user (<code>bt</code>) inside the container, I limited the potential damage in case of a breach or compromise. If the <code>bt</code> user account was compromised, the attacker would not gain root privileges within the container or access to other containers or resources on the host system.</p><p>Additionally, since all containers&apos; root users were mapped to the same host user ID (UID=1000000), any resources shared among containers would be accessible to the root user of any compromised container. By explicitly granting permissions only to the <code>bt</code> user, I ensured that a breach of the BitTorrent container would not grant access to resources shared by other containers.</p><p><strong>Learnings and Conclusion</strong></p><p>This experience taught me several valuable lessons:</p><p><strong>Understand user and permission mappings</strong>: When working with containers, it&apos;s crucial to understand how user and group IDs are mapped between the host and container environments, as well as the security implications of these mappings.</p><p><strong>Limitations of generic solutions</strong>: Generic solutions found online may not always work as expected, especially when dealing with specific system configurations or kernel versions. Tailored configurations based on thorough understanding and investigation are often necessary.</p><p><strong>Security-conscious configurations</strong>: Granting broad permissions (e.g., mode 777) should be avoided whenever possible. Instead, configure permissions specifically for the users and groups required by the application, following the principle of least privilege.</p><p><strong>Containerization best practices</strong>: Running services as non-root users within containers and limiting resource sharing between containers can help mitigate the impact of potential breaches or compromises.</p><p>While initially seeming like a trivial task, mounting a host directory with write access inside an LXC container proved to be a complex challenge. However, through research, experimentation, and a deeper understanding of the underlying concepts, I was able to implement a secure and tailored solution for my BitTorrent download service.</p><p><strong>Appendix: Root Access to Mounted Host Directories</strong></p><p>After successfully setting up the <code>bt</code> user and granting it the necessary permissions to access the mounted host directory, I noticed a peculiar behavior: the root user inside the container could also access and modify files within the mounted host directory, despite not explicitly granting it those permissions.</p><p>Initially, I found this puzzling since I had carefully configured the permissions to allow only the <code>bt</code> user (UID=1001, mapped to UID=1001001 on the host) access to the host directory. However, further investigation revealed that this behavior is an intentional design choice in LXC containers.</p><p>According to the LXC documentation and community discussions, once a resource (such as a mounted host directory) is granted to any user inside a container, the root user of that container automatically gains the same access to that resource. This is because the root user has unrestricted privileges within the container&apos;s namespace, regardless of the permissions set for other users.</p><p>The rationale behind this design decision is to maintain the expected behavior and functionality of the root user within the container environment. In traditional Linux systems, the root user has complete control over the system, including the ability to override permissions and access any resource. LXC containers aim to emulate this behavior as closely as possible while still providing isolation and security boundaries.</p><p>While this behavior may seem counterintuitive from a strict permission standpoint, it aligns with the principles of containerization and the separation of concerns between the host and container environments. The host system&apos;s permissions are respected for controlling access to resources from the host, while the container&apos;s root user retains its privileged status within the container&apos;s namespace.</p><p>It&apos;s important to note that this behavior does not compromise the overall security of the system, as the root user within the container is still confined to the container&apos;s isolated environment and cannot directly access or modify resources on the host system without proper permissions.</p><p>In my case, although the root user inside the BitTorrent container could access the mounted host directory, it remained confined within the container&apos;s boundaries. By running the BitTorrent service as the non-root <code>bt</code> user, I limited the potential damage in case of a breach or compromise, as an attacker would not gain root privileges within the container or access to other containers or resources on the host system.</p><p>While this &quot;weird thing&quot; may seem like a quirk or potential security concern at first glance, it is an intentional design choice in LXC containers to maintain the expected behavior and functionality of the root user within the container&apos;s namespace, while still providing isolation and security boundaries between the host and container environments.</p><p><strong>Appendix: Using <code>idmap</code> to Mitigate Permission Overlaps</strong></p><p>While the default user and group ID mapping between the host and containers can be a convenient and straightforward approach, it can also lead to potential permission overlaps between containers, which may introduce security risks.</p><p>To mitigate this risk and ensure better isolation of permissions between containers, the <code>idmap</code> technique can be employed. Instead of relying on the default user and group ID mapping range, <code>idmap</code> allows you to specify a unique mapping for each container, effectively isolating the permissions granted to specific user IDs and group IDs within that container.</p><p>Here&apos;s an example of how <code>idmap</code> could be used to achieve better permission isolation for a specific user ID and group ID:</p><p><strong>Map a specific container user ID and group ID to dedicated host IDs</strong>:</p><pre><code>lxc config set &lt;container-name&gt; raw.idmap &quot;both 1001 1033&quot;
</code></pre><p>This command maps both the user ID 1001 and the group ID 1001 inside the container to the host user ID 1033 and host group ID 1033, respectively. By using a distinct user ID and group ID (1033) on the host, you can avoid potential conflicts or confusion with existing IDs.</p><p><strong>Create the user and group, and set permissions within the dedicated mapping</strong>:<br>Within the container, create the user with UID=1001 and the group with GID=1001, and set permissions accordingly. On the host system, ensure that the resources you want to grant access to have the appropriate permissions for the host user ID 1033 and host group ID 1033.</p><p>By using <code>idmap</code> with the &quot;both&quot; option and a distinct user ID and group ID on the host (1033), you can isolate the mapping for a specific user ID and group ID simultaneously, preventing permission overlaps for that user ID and group ID between containers. If you grant permissions to the user ID 1001 and group ID 1001 within one container, it will not affect or grant the same permissions to the corresponding user ID 1001 and group ID 1001 in other containers, as they are mapped to different host user IDs and group IDs.</p><p>This approach provides an additional layer of security and isolation for the specific user ID and group ID you want to isolate, ensuring that a compromised container cannot leverage those permissions to access resources across other containers.</p><p>Using a distinct and less commonly used user ID and group ID (such as 1033) on the host side can help avoid potential conflicts or confusion with existing IDs, making the configuration more clear and maintainable.</p><p>It&apos;s important to note that while <code>idmap</code> can mitigate permission overlaps for specific user IDs and group IDs, it should be used in conjunction with other security best practices, such as running services as non-root users, limiting resource sharing between containers, and following the principle of least privilege when granting permissions.</p><p></p><hr><p>&#x2728; This blog was written by AI! &#x1F916;</p><hr>]]></content:encoded></item><item><title><![CDATA[Cursor小试牛刀]]></title><description><![CDATA[<p>&#x521A;&#x542C;&#x4E86;Lex Fridman&#x5BF9;Cursor&#x5F00;&#x53D1;&#x56E2;&#x961F;&#x7684;&#x91C7;&#x8BBF;&#xFF0C;&#x987A;&#x4FBF;&#x5206;&#x4EAB;&#x4E00;&#x4E0B;&#x81EA;&#x5DF1;&#x4F7F;&#x7528;Cursor&#x7684;&#x4F53;&#x9A8C;&#x3002;</p><p>&#x4E0A;&#x4E2A;&#x6708;&#xFF0C;&#x6211;&#x6CE8;&#x518C;&#x5E76;&#x8BD5;&#x7528;&#x4E86;Cursor&#x3002;&#x5728;&#x4E3A;&#x671F;&#x534A;&#x4E2A;&#x6708;&#x7684;</p>]]></description><link>https://blog.optman.net/cursor/</link><guid isPermaLink="false">67078bd68eb62400015d3b77</guid><dc:creator><![CDATA[optman]]></dc:creator><pubDate>Thu, 10 Oct 2024 08:14:48 GMT</pubDate><content:encoded><![CDATA[<p>&#x521A;&#x542C;&#x4E86;Lex Fridman&#x5BF9;Cursor&#x5F00;&#x53D1;&#x56E2;&#x961F;&#x7684;&#x91C7;&#x8BBF;&#xFF0C;&#x987A;&#x4FBF;&#x5206;&#x4EAB;&#x4E00;&#x4E0B;&#x81EA;&#x5DF1;&#x4F7F;&#x7528;Cursor&#x7684;&#x4F53;&#x9A8C;&#x3002;</p><p>&#x4E0A;&#x4E2A;&#x6708;&#xFF0C;&#x6211;&#x6CE8;&#x518C;&#x5E76;&#x8BD5;&#x7528;&#x4E86;Cursor&#x3002;&#x5728;&#x4E3A;&#x671F;&#x534A;&#x4E2A;&#x6708;&#x7684;Pro&#x8BD5;&#x7528;&#x671F;&#x7ED3;&#x675F;&#x4E4B;&#x524D;&#xFF0C;&#x6211;&#x6210;&#x529F;&#x4E3A;<strong><a href="https://github.com/optman/minivtun-android">minivtun-android</a></strong>&#x6DFB;&#x52A0;&#x4E86;&#x5E94;&#x7528;&#x6307;&#x5B9A;/&#x8FC7;&#x6EE4;&#x7684;&#x529F;&#x80FD;&#x2014;&#x2014;&#x8FD9;&#x662F;&#x4E00;&#x4E2A;&#x6211;&#x4E00;&#x76F4;&#x60F3;&#x5B9E;&#x73B0;&#xFF0C;&#x4F46;&#x6CA1;&#x6709;&#x4FE1;&#x5FC3;&#x53BB;&#x5B8C;&#x6210;&#x7684;&#x529F;&#x80FD;&#x3002;&#x6211;&#x8FD8;&#x987A;&#x5229;&#x5B8C;&#x6210;&#x4E86;&#x4EE3;&#x7801;&#x7684;&#x5347;&#x7EA7;&#x5DE5;&#x4F5C;&#xFF0C;&#x73B0;&#x5728;&#x652F;&#x6301;Android 11&#xFF0C;&#x5E76;&#x4E14;&#x53EF;&#x4EE5;&#x7F16;&#x8BD1;release&#x7248;&#x672C;&#x4E86;&#xFF0C;&#x751A;&#x81F3;&#x8FD8;&#x6DFB;&#x52A0;&#x4E86;app&#x56FE;&#x6807;&#x3002;&#x53EF;&#x4EE5;&#x8BF4;&#xFF0C;Android&#x7684;Java&#x4EE3;&#x7801;&#x51E0;&#x4E4E;&#x90FD;&#x662F;&#x901A;&#x8FC7;Cursor&#x7684;&#x81EA;&#x52A8;&#x751F;&#x6210;&#x529F;&#x80FD;&#x5B8C;&#x6210;&#x7684;&#xFF0C;&#x56E0;&#x4E3A;&#x6211;&#x5DF2;&#x7ECF;&#x591A;&#x5E74;&#x6CA1;&#x6709;&#x7F16;&#x5199;Android&#x4EE3;&#x7801;&#x4E86;&#x3002;&#x5982;&#x679C;&#x6CA1;&#x6709;Cursor&#x7684;&#x5E2E;&#x52A9;&#xFF0C;&#x5373;&#x4FBF;&#x901A;&#x8FC7;&#x67E5;&#x9605;&#x6587;&#x6863;&#x81EA;&#x5DF1;&#x4E5F;&#x80FD;&#x5B8C;&#x6210;&#x8FD9;&#x9879;&#x4EFB;&#x52A1;&#xFF0C;&#x4F46;&#x8017;&#x8D39;&#x7684;&#x7CBE;&#x529B;&#x548C;&#x65F6;&#x95F4;&#x5C06;&#x975E;&#x5E38;&#x5DE8;&#x5927;&#xFF0C;&#x51B5;&#x4E14;&#x6211;&#x4E5F;&#x6CA1;&#x6709;&#x6DF1;&#x5165;&#x5F00;&#x53D1;Android&#x7684;&#x6253;&#x7B97;&#x3002;<strong><a href="https://github.com/optman/minivtun-android">minivtun-android</a></strong>&#x672C;&#x8EAB;&#x5C31;&#x662F;&#x57FA;&#x4E8E;&#x4F8B;&#x5B50;&#x5DE5;&#x7A0B;<strong>toyvpn</strong>&#x7A0D;&#x4F5C;&#x4FEE;&#x6539;&#x800C;&#x6765;&#x7684;&#xFF0C;&#x5E95;&#x5C42;&#x4E3B;&#x8981;&#x4F9D;&#x8D56;<strong><a href="https://github.com/optman/minivtun">minivtun</a></strong>&#x7684;Rust&#x6A21;&#x5757;&#xFF0C;&#x5BF9;&#x4E8E;&#x754C;&#x9762;&#x7684;&#x90E8;&#x5206;&#x53EA;&#x80FD;&#x51D1;&#x5408;&#x7740;&#x7528;&#x3002;</p><p>&#x518D;&#x6765;&#x8BF4;&#x8BF4;Cursor&#x7684;Tab&#x529F;&#x80FD;&#xFF0C;&#x5B9E;&#x5728;&#x662F;&#x592A;&#x65B9;&#x4FBF;&#x4E86;&#x3002;&#x5728;&#x5F00;&#x53D1;&#x8FC7;&#x7A0B;&#x4E2D;&#xFF0C;&#x6D89;&#x53CA;&#x5230;JNI&#x63A5;&#x53E3;&#x65F6;&#xFF0C;&#x6B63;&#x5F53;&#x6211;&#x4E3A;&#x5982;&#x4F55;&#x5C06;Rust&#x5BF9;&#x8C61;&#x8F6C;&#x6362;&#x4E3A;Java&#x5BF9;&#x8C61;&#x800C;&#x72AF;&#x6101;&#x65F6;&#xFF0C;&#x53EA;&#x9700;&#x8981;&#x6309;&#x4E00;&#x4E0B;Tab&#x952E;&#xFF0C;Cursor&#x5C31;&#x81EA;&#x52A8;&#x751F;&#x6210;&#x4E86;&#x5BF9;&#x5E94;&#x7684;&#x4EE3;&#x7801;&#xFF0C;&#x8BA9;&#x6211;&#x611F;&#x5230;&#x975E;&#x5E38;&#x60CA;&#x8273;&#x3002;&#x5982;&#x679C;&#x662F;&#x4EE5;&#x5F80;&#xFF0C;&#x6211;&#x53EF;&#x80FD;&#x9700;&#x8981;&#x67E5;&#x534A;&#x5929;&#x7684;&#x6587;&#x6863;&#x3002;&#x4E0D;&#x5F97;&#x4E0D;&#x8BF4;&#xFF0C;Cursor&#x786E;&#x5B9E;&#x5927;&#x5927;&#x63D0;&#x5347;&#x4E86;&#x5F00;&#x53D1;&#x6548;&#x7387;&#x3002;</p><p>&#x4E0D;&#x8FC7;&#xFF0C;&#x4E5F;&#x4E0D;&#x8981;&#x795E;&#x8BDD;Cursor&#x3002;&#x5982;&#x679C;&#x5B8C;&#x5168;&#x6CA1;&#x6709;&#x7F16;&#x7A0B;&#x57FA;&#x7840;&#xFF0C;&#x60F3;&#x901A;&#x8FC7;&#x5B83;&#x5F00;&#x53D1;&#x51FA;&#x5B8C;&#x6574;&#x7684;App&#x8FD8;&#x662F;&#x6709;&#x4E9B;&#x4E0D;&#x73B0;&#x5B9E;&#x7684;&#xFF08;&#x867D;&#x7136;&#x53EF;&#x4EE5;&#x4E00;&#x6B65;&#x751F;&#x6210;&#x4EE3;&#x7801;&#xFF0C;&#x4F46;&#x540E;&#x7EED;&#x4FEE;&#x6539;&#x7EDD;&#x975E;&#x6613;&#x4E8B;&#xFF09;&#x3002;&#x5BF9;&#x6211;&#x6765;&#x8BF4;&#xFF0C;Cursor&#x7684;&#x4E3B;&#x8981;&#x4F5C;&#x7528;&#x662F;&#x8282;&#x7701;&#x5927;&#x91CF;&#x7684;&#x7F16;&#x7801;&#x548C;&#x67E5;&#x9605;&#x6587;&#x6863;&#x7684;&#x65F6;&#x95F4;&#x3002;&#x4F60;&#x77E5;&#x9053;&#x4E0B;&#x4E00;&#x6B65;&#x8BE5;&#x505A;&#x4EC0;&#x4E48;&#xFF0C;&#x4F46;&#x8BB0;&#x4E0D;&#x4F4F;&#x5177;&#x4F53;&#x7EC6;&#x8282;&#xFF0C;&#x7279;&#x522B;&#x662F;&#x5BF9;&#x4E0D;&#x5E38;&#x7528;&#x7684;&#x8BED;&#x8A00;&#x548C;&#x6846;&#x67B6;&#x3002;&#x8FD9;&#x65F6;Cursor&#x80FD;&#x591F;&#x81EA;&#x52A8;&#x5E2E;&#x4F60;&#x60F3;&#x5230;&#xFF0C;&#x5E76;&#x751F;&#x6210;&#x5BF9;&#x5E94;&#x4EE3;&#x7801;&#xFF0C;&#x5B9E;&#x5728;&#x662F;&#x518D;&#x597D;&#x4E0D;&#x8FC7;&#x4E86;&#x3002;&#x5982;&#x679C;&#x751F;&#x6210;&#x7684;&#x4EE3;&#x7801;&#x4E0D;&#x592A;&#x5408;&#x9002;&#xFF0C;&#x4F60;&#x8FD8;&#x53EF;&#x4EE5;&#x6307;&#x51FA;&#x95EE;&#x9898;&#xFF0C;&#x8BA9;&#x5B83;&#x8FDB;&#x884C;&#x4FEE;&#x6539;&#x3002;&#x5C31;&#x50CF;&#x662F;&#x6709;&#x4E86;&#x4E00;&#x4E2A;&#x52A9;&#x624B;&#xFF0C;&#x52A8;&#x52A8;&#x5634;&#x5DF4;&#x5C31;&#x6709;&#x4EBA;&#x5E2E;&#x4F60;&#x641E;&#x5B9A;&#x5DE5;&#x4F5C;&#xFF0C;&#x539F;&#x6765;&#x5F53;&#x201C;&#x9886;&#x5BFC;&#x201D;&#x7ADF;&#x7136;&#x8FD9;&#x4E48;&#x723D;&#x3002;</p><p>&#x9700;&#x8981;&#x6CE8;&#x610F;&#x7684;&#x662F;&#xFF0C;Cursor&#x751F;&#x6210;&#x7684;&#x4EE3;&#x7801;&#x5E76;&#x975E;&#x6700;&#x4F18;&#xFF0C;&#x66F4;&#x591A;&#x65F6;&#x5019;&#x53EA;&#x662F;&#x201C;&#x80FD;&#x7528;&#x201D;&#x800C;&#x5DF2;&#x3002;&#x6709;&#x65F6;&#x5B83;&#x7684;&#x601D;&#x8DEF;&#x53EF;&#x80FD;&#x4E0E;&#x4F60;&#x7684;&#x60F3;&#x6CD5;&#x4E0D;&#x4E00;&#x81F4;&#xFF0C;&#x8FD9;&#x65F6;&#x5019;&#x8FD8;&#x5F97;&#x9760;&#x7ECF;&#x9A8C;&#x8FDB;&#x884C;&#x7504;&#x522B;&#x3002;&#x76EE;&#x524D;Cursor&#x8FD8;&#x6CA1;&#x6709;&#x50CF;Aider&#x90A3;&#x6837;&#x7684;&#x81EA;&#x52A8;&#x8FED;&#x4EE3;&#x529F;&#x80FD;&#xFF0C;&#x56E0;&#x6B64;&#x4F60;&#x9700;&#x8981;&#x53CD;&#x590D;&#x624B;&#x52A8;&#x63D0;&#x793A;&#x5B83;&#x3002;&#x4E3A;&#x4E86;&#x5B8C;&#x6210;&#x9879;&#x76EE;&#x4EE3;&#x7801;&#x5347;&#x7EA7;&#xFF0C;&#x5C24;&#x5176;&#x662F;&#x6D88;&#x9664;&#x5404;&#x79CD;&#x8B66;&#x544A;&#x4FE1;&#x606F;&#xFF0C;&#x6211;&#x82B1;&#x4E86;&#x4E0D;&#x5C11;&#x65F6;&#x95F4;&#xFF0C;&#x8017;&#x8D39;&#x4E86;&#x5927;&#x534A;&#x7684;&#x9AD8;&#x7EA7;&#x6A21;&#x578B;&#x8C03;&#x7528;&#x989D;&#x5EA6;&#x3002;&#x7531;&#x4E8E;&#x5BF9;Android&#x7684;&#x65B0;SDK&#x6846;&#x67B6;&#x5B8C;&#x5168;&#x4E0D;&#x4E86;&#x89E3;&#xFF0C;&#x6211;&#x53EA;&#x80FD;&#x8BA9;AI&#x4E0D;&#x65AD;&#x5C1D;&#x8BD5;&#xFF0C;&#x81EA;&#x5DF1;&#x5219;&#x50CF;&#x4E2A;&#x673A;&#x5668;&#x4EBA;&#x4E00;&#x6837;&#x4E0D;&#x65AD;&#x5C06;&#x7ED3;&#x679C;&#x53CD;&#x9988;&#x7ED9;&#x5B83;&#xFF08;&#x8FD9;&#x79CD;&#x65F6;&#x5019;&#x4EBA;&#x53CD;&#x5012;&#x6210;&#x4E86;&#x673A;&#x5668;&#x7684;&#x52A9;&#x624B;&#xFF09;&#x3002;&#x5982;&#x679C;&#x65E5;&#x5E38;&#x7F16;&#x7801;&#x90FD;&#x662F;&#x8FD9;&#x6837;&#xFF0C;&#x90A3;&#x4E5F;&#x592A;&#x67AF;&#x71E5;&#x4E4F;&#x5473;&#x4E86;&#x3002;&#x53CB;&#x60C5;&#x63D0;&#x793A;&#xFF1A;&#x4E0D;&#x8981;&#x6307;&#x671B;&#x4E00;&#x6B21;&#x6027;&#x8BA9;AI&#x505A;&#x592A;&#x591A;&#x4E8B;&#xFF0C;&#x4E00;&#x65E6;&#x67D0;&#x4E2A;&#x6B65;&#x9AA4;&#x51FA;&#x9519;&#xFF0C;&#x8FD8;&#x5F97;&#x4ECE;&#x5934;&#x518D;&#x6765;&#x3002;&#x6240;&#x4EE5;&#xFF0C;&#x5F53;&#x201C;&#x9886;&#x5BFC;&#x201D;&#x4E5F;&#x4E0D;&#x662F;&#x90A3;&#x4E48;&#x597D;&#x5F53;&#x7684;&#xFF0C;&#x4E0B;&#x5C5E;&#x4E0D;&#x7ED9;&#x529B;&#x65F6;&#xFF0C;&#x4F60;&#x53EF;&#x80FD;&#x4F1A;&#x89C9;&#x5F97;&#x8FD8;&#x4E0D;&#x5982;&#x81EA;&#x5DF1;&#x52A8;&#x624B;&#x6765;&#x5F97;&#x5FEB;&#x3002;</p><p>&#x6700;&#x540E;&#xFF0C;&#x597D;&#x4E0D;&#x5BB9;&#x6613;&#x628A;&#x4EE3;&#x7801;&#x5347;&#x7EA7;&#x5230;&#x4E86;&#x652F;&#x6301;Android 11&#x7684;&#x7248;&#x672C;&#xFF0C;&#x4E0D;&#x7981;&#x611F;&#x6168;&#xFF1A;&#x8FD9;SDK&#x7684;&#x53D8;&#x5316;&#x4E5F;&#x592A;&#x5927;&#x4E86;&#x5427;&#xFF01;&#x7EF4;&#x62A4;Android&#x4EE3;&#x7801;&#x771F;&#x662F;&#x9EBB;&#x70E6;&#x3002;&#x8981;&#x4E0D;&#x662F;&#x6709;AI&#x8F85;&#x52A9;&#xFF0C;&#x6211;&#x80AF;&#x5B9A;&#x6CA1;&#x52C7;&#x6C14;&#x53BB;&#x5347;&#x7EA7;&#x8FD9;&#x6BB5;&#x4EE3;&#x7801;&#x3002;</p><p>&#x901A;&#x8FC7;&#x8BD5;&#x7528;Cursor&#xFF0C;&#x6211;&#x610F;&#x8BC6;&#x5230;&#xFF0C;AI&#x8F85;&#x52A9;&#x7F16;&#x7A0B;&#x7684;&#x6700;&#x5927;&#x4EF7;&#x503C;&#x5728;&#x4E8E;&#x5B83;&#x80FD;&#x7ED9;&#x4E88;&#x4EBA;&#x6311;&#x6218;&#x964C;&#x751F;&#x9886;&#x57DF;&#x7684;&#x52C7;&#x6C14;&#x3002;&#x56E0;&#x4E3A;&#x4F60;&#x77E5;&#x9053;&#x6709;&#x4E00;&#x4E2A;&#x201C;&#x4F19;&#x4F34;&#x201D;&#x53EF;&#x4EE5;&#x4E00;&#x8DEF;&#x7ED9;&#x4F60;&#x5EFA;&#x8BAE;&#xFF0C;&#x867D;&#x7136;&#x6709;&#x65F6;&#x4E5F;&#x4E0D;&#x592A;&#x9760;&#x8C31;&#xFF0C;&#x4F46;&#x5B83;&#x59CB;&#x7EC8;&#x4E0D;&#x538C;&#x5176;&#x70E6;&#xFF0C;&#x6C38;&#x4E0D;&#x653E;&#x5F03;&#x3002;</p>]]></content:encoded></item><item><title><![CDATA[Android的VPN底层代码探幽]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>&#x5199;<a href="https://blog.optman.net/minivtun-android">minivtun_android</a>&#x7684;&#x65F6;&#x5019;&#xFF0C;&#x4E3A;&#x4E86;&#x628A;minivtun&#x4F5C;&#x4E3A;&#x5168;&#x5C40;vpn&#xFF08;&#x8DEF;&#x7531;&#x8BBE;&#x4E3A;0.0.0.0/0&#xFF0C;::/0&#xFF09;&#xFF0C;&#x540C;&#x65F6;&#x8FD8;&#x628A;minivtun&#x81EA;&#x5DF1;&#x53D1;&#x8D77;&#x7684;&#x6D41;&#x91CF;&#x6392;&#x9664;&#x5728;&#x5916;&#xFF0C;&#x539F;&#x8BA1;&#x5212;</p>]]></description><link>https://blog.optman.net/android-vpnservice-code/</link><guid isPermaLink="false">63c7b0d1c976820001972fa4</guid><category><![CDATA[android]]></category><dc:creator><![CDATA[optman]]></dc:creator><pubDate>Wed, 18 Jan 2023 08:48:17 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>&#x5199;<a href="https://blog.optman.net/minivtun-android">minivtun_android</a>&#x7684;&#x65F6;&#x5019;&#xFF0C;&#x4E3A;&#x4E86;&#x628A;minivtun&#x4F5C;&#x4E3A;&#x5168;&#x5C40;vpn&#xFF08;&#x8DEF;&#x7531;&#x8BBE;&#x4E3A;0.0.0.0/0&#xFF0C;::/0&#xFF09;&#xFF0C;&#x540C;&#x65F6;&#x8FD8;&#x628A;minivtun&#x81EA;&#x5DF1;&#x53D1;&#x8D77;&#x7684;&#x6D41;&#x91CF;&#x6392;&#x9664;&#x5728;&#x5916;&#xFF0C;&#x539F;&#x8BA1;&#x5212;&#x4F7F;&#x7528;<a href="https://developer.android.com/reference/android/net/VpnService#protect(int)">VpnService.protect</a>&#x51FD;&#x6570;&#x7684;&#xFF0C;&#x6700;&#x540E;&#x53D1;&#x73B0;&#x5E76;&#x4E0D;&#x597D;&#x4F7F;&#xFF0C;&#x6700;&#x540E;&#x662F;&#x901A;&#x8FC7;<a href="https://developer.android.com/reference/android/net/VpnService.Builder#addDisallowedApplication(java.lang.String)">VpnService.Builder.AddDisallowApplications</a>&#x628A;&#x81EA;&#x8EAB;id&#x52A0;&#x5165;&#x89E3;&#x51B3;&#x7684;&#xFF08;&#x8FD9;&#x4E2A;&#x65B9;&#x6CD5;&#x66F4;&#x7B80;&#x5355;&#xFF0C;&#x5F53;&#x521D;&#x600E;&#x4E48;&#x6CA1; <s>&#x60F3;</s> &#x641C;&#x5230;&#xFF01;&#xFF09;&#x3002;</p>
<p>&#x4E3A;&#x4E86;&#x89E3;&#x7B54;protect&#x4E0D;&#x751F;&#x6548;&#x7684;&#x8FD9;&#x4E2A;&#x7591;&#x95EE;&#xFF0C;&#x6211;&#x51B3;&#x5B9A;&#x8BFB;&#x4E00;&#x8BFB;android&#x7684;vpn service&#x5E95;&#x5C42;&#x4EE3;&#x7801;&#xFF0C;&#x540C;&#x65F6;&#x4E86;&#x89E3;&#x4E00;&#x4E0B;&#x5B83;&#x662F;&#x5982;&#x4F55;&#x8BBE;&#x7F6E;&#x8DEF;&#x7531;&#x89C4;&#x5219;&#x7684;&#xFF08;&#x5982;&#x4F55;&#x8BA9;&#x6307;&#x5B9A;&#x5E94;&#x7528;&#x8D70;&#x6216;&#x4E0D;&#x8D70;vpn&#xFF09;&#x3002;</p>
<p>&#x4EE5;&#x524D;&#x5728;Linux&#x547D;&#x4EE4;&#x884C;&#x4E0B;&#xFF0C;&#x6211;&#x662F;&#x901A;&#x8FC7;&#x8BBE;&#x5B9A;minivtun&#x7684;fwmark&#x53C2;&#x6570;&#xFF0C;&#x7136;&#x540E;&#x4F7F;&#x7528;ip rule&#x6307;&#x5B9A;fwmark&#x8D70;&#x4E0D;&#x540C;&#x7684;route table&#x7684;&#xFF0C;android&#x4F1A;&#x6709;&#x4EC0;&#x4E48;&#x4E0D;&#x540C;&#x4E48;&#xFF1F;</p>
<p>&#x4EE5;&#x4E0B;&#x5C31;&#x662F;&#x4EE3;&#x7801;&#x8FFD;&#x8E2A;&#x7684;&#x8FC7;&#x7A0B;&#xFF0C;&#x7ED3;&#x679C;&#x6BD4;&#x6211;&#x60F3;&#x8C61;&#x7684;&#x8981;&#x590D;&#x6742;&#x3002;&#x4F46;&#x4ECE;&#x6700;&#x540E;&#x7684;&#x5B9E;&#x73B0;&#x65B9;&#x5F0F;&#x6765;&#x770B;&#xFF0C;android&#x7684;&#x5B9E;&#x73B0;&#x4E0E;&#x547D;&#x4EE4;&#x884C;&#x5E76;&#x6CA1;&#x6709;&#x5DEE;&#x522B;&#xFF0C;&#x6700;&#x7EC8;&#x8FD8;&#x662F;&#x5F97;&#x4F9D;&#x9760; fwmark&#x548C;ip rule&#x6765;&#x5B9E;&#x73B0;&#x3002;</p>
<ul>
<li><a href="#disallowedApplications">disallowedApplications&#x7684;&#x5B9E;&#x73B0;</a></li>
<li><a href="#protect">protect&#x7684;&#x5B9E;&#x73B0;</a></li>
<li><a href="#libc">Libc</a></li>
<li><a href="#netdclient">NetdClient</a></li>
<li><a href="#netd">Netd</a></li>
</ul>
<h1 id="a-iddisallowedapplicationsa-disallowedapplications%E7%9A%84%E5%AE%9E%E7%8E%B0"><a id="disallowedApplications"></a> disallowedApplications&#x7684;&#x5B9E;&#x73B0;</h1>
<p>&#x6307;&#x5B9A;app&#x7ED5;&#x8FC7;vpn&#xFF0C;&#x9700;&#x8981;&#x5148;&#x628A;app&#x8F6C;&#x6210;uid&#xFF0C;&#x7136;&#x540E;&#xFF08;&#x8FDC;&#x7A0B;&#x8C03;&#x7528;&#xFF09;&#x901A;&#x77E5;netd&#x8FDB;&#x7A0B;&#xFF0C;&#x540E;&#x8005;&#x8D1F;&#x8D23;&#x5B8C;&#x6210;&#x5177;&#x4F53;&#x7684;&#x64CD;&#x4F5C;&#x3002;</p>
<p><a href="https://cs.android.com/android/platform/superproject/+/master:frameworks/base/services/core/java/com/android/server/connectivity/Vpn.java;l=1819;drc=f42a611faa92d6bff1dfeade9b4e9775e7d15b9f?q=allowedApplications&amp;ss=android%2Fplatform%2Fsuperproject">frameworks/base/services/core/java/com/android/server/connectivity/Vpn.java</a></p>
<pre><code>   /**
     * Triggers an update of the VPN network&apos;s excluded UIDs if a VPN is running.
     */
    public synchronized void refreshPlatformVpnAppExclusionList() {
        updateAppExclusionList(getAppExclusionList(mPackage));
    }
    
    private synchronized void updateAppExclusionList(@NonNull List&lt;String&gt; excludedApps) {
        // Re-build and update NetworkCapabilities via NetworkAgent.
        if (mNetworkAgent != null) {
            // Only update the platform VPN
            if (isIkev2VpnRunner()) {
                mConfig.disallowedApplications = List.copyOf(excludedApps);
                mNetworkCapabilities = new NetworkCapabilities.Builder(mNetworkCapabilities)
                        .setUids(createUserAndRestrictedProfilesRanges(
                                mUserId, null /* allowedApplications */, excludedApps))
                        .build();
                setVpnNetworkPreference(getSessionKeyLocked(),
                        createUserAndRestrictedProfilesRanges(mUserId,
                                mConfig.allowedApplications, mConfig.disallowedApplications));
                doSendNetworkCapabilities(mNetworkAgent, mNetworkCapabilities);
            }
        }
    }
    
       private void setVpnNetworkPreference(String session, Set&lt;Range&lt;Integer&gt;&gt; ranges) {
        BinderUtils.withCleanCallingIdentity(
                () -&gt; mConnectivityManager.setVpnDefaultForUids(session, ranges));
    }
    
    

/**
     * Creates a {@link Set} of non-intersecting {@code Range&lt;Integer&gt;} objects including all UIDs
     * associated with one user, and any restricted profiles attached to that user.
     *
     * &lt;p&gt;If one of {@param allowedApplications} or {@param disallowedApplications} is provided,
     * the UID ranges will match the app list specified there. Otherwise, all UIDs
     * in each user and profile will be included.
     *
     * @param userId The userId to create UID ranges for along with any of its restricted
     *                   profiles.
     * @param allowedApplications (optional) List of applications to allow.
     * @param disallowedApplications (optional) List of applications to deny.
     */
    @VisibleForTesting
    Set&lt;Range&lt;Integer&gt;&gt; createUserAndRestrictedProfilesRanges(@UserIdInt int userId,
            @Nullable List&lt;String&gt; allowedApplications,
            @Nullable List&lt;String&gt; disallowedApplications) {

</code></pre>
<p><a href="https://cs.android.com/android/platform/superproject/+/master:packages/modules/Connectivity/framework/src/android/net/ConnectivityManager.java;drc=f42a611faa92d6bff1dfeade9b4e9775e7d15b9f;l=1493">packages/modules/Connectivity/framework/src/android/net/ConnectivityManager.java</a></p>
<pre><code>/**
     * Inform the system that this VPN session should manage the passed UIDs.
     *
     * A VPN with the specified session ID may call this method to inform the system that the UIDs
     * in the specified range are subject to a VPN.
     * When this is called, the system will only choose a VPN for the default network of the UIDs in
     * the specified ranges.
     *
     * This method declares that the UIDs in the range will only have a VPN for their default
     * network, but does not block the UIDs from accessing other networks (permissions allowing) by
     * explicitly requesting it with the {@link Network} API.
     * Compare {@link #setRequireVpnForUids(boolean, Collection)}, which does not affect what
     * network the UIDs get as default, but will block them from accessing non-VPN networks.
     *
     * @param session The VPN session which manages the passed UIDs.
     * @param ranges The uid ranges which will treat VPN as their only default network.
     *
     * @hide
     */
    @RequiresPermission(anyOf = {
            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
            android.Manifest.permission.NETWORK_STACK,
            android.Manifest.permission.NETWORK_SETTINGS})
    @SystemApi(client = MODULE_LIBRARIES)
    public void setVpnDefaultForUids(@NonNull String session,
            @NonNull Collection&lt;Range&lt;Integer&gt;&gt; ranges) {
        Objects.requireNonNull(ranges);
        final UidRange[] rangesArray = getUidRangeArray(ranges);
        try {
            mService.setVpnNetworkPreference(session, rangesArray);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

</code></pre>
<p><a href="https://cs.android.com/android/platform/superproject/+/master:packages/modules/Connectivity/service/src/com/android/server/ConnectivityService.java;l=11284;drc=f42a611faa92d6bff1dfeade9b4e9775e7d15b9f;bpv=1;bpt=1">packages/modules/Connectivity/service/src/com/android/server/ConnectivityService.java</a></p>
<pre><code>/**
     * Sets the specified UIDs to get/receive the VPN as the only default network.
     *
     * Calling this will overwrite the existing network preference for this session, and the
     * specified UIDs won&apos;t get any default network when no VPN is connected.
     *
     * @param session The VPN session which manages the passed UIDs.
     * @param ranges The uid ranges which will treat VPN as the only preferred network. Clear the
     *               setting for this session if the array is empty. Null is not allowed, the
     *               method will use {@link Objects#requireNonNull(Object)} to check this variable.
     * @hide
     */
    @Override
    public void setVpnNetworkPreference(String session, UidRange[] ranges) {
        Objects.requireNonNull(ranges);
        enforceNetworkStackOrSettingsPermission();
        final UidRange[] sortedRanges = UidRangeUtils.sortRangesByStartUid(ranges);
        if (UidRangeUtils.sortedRangesContainOverlap(sortedRanges)) {
            throw new IllegalArgumentException(
                    &quot;setVpnNetworkPreference: Passed UID ranges overlap&quot;);
        }

        mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_VPN_NETWORK_PREFERENCE,
                new VpnNetworkPreferenceInfo(session,
                        new ArraySet&lt;UidRange&gt;(Arrays.asList(ranges)))));
    }
    
    public void handleMessage(Message msg) {
            switch (msg.what) {
                    case EVENT_SET_VPN_NETWORK_PREFERENCE:
                    handleSetVpnNetworkPreference((VpnNetworkPreferenceInfo) msg.obj);
                    break;
         
               
    private void handleSetVpnNetworkPreference(VpnNetworkPreferenceInfo preferenceInfo) {
        Log.d(TAG, &quot;handleSetVpnNetworkPreference: preferenceInfo = &quot; + preferenceInfo);

        mVpnNetworkPreferences = mVpnNetworkPreferences.minus(preferenceInfo.getKey());
        mVpnNetworkPreferences = mVpnNetworkPreferences.plus(preferenceInfo);

        removeDefaultNetworkRequestsForPreference(PREFERENCE_ORDER_VPN);
        addPerAppDefaultNetworkRequests(createNrisForVpnNetworkPreference(mVpnNetworkPreferences));
        // Finally, rematch.
        rematchAllNetworksAndRequests();
    }
                    

   private void updateVpnUidRanges(boolean add, NetworkAgentInfo nai, Set&lt;UidRange&gt; uidRanges) {
        int[] exemptUids = new int[2];
        // TODO: Excluding VPN_UID is necessary in order to not to kill the TCP connection used
        // by PPTP. Fix this by making Vpn set the owner UID to VPN_UID instead of system when
        // starting a legacy VPN, and remove VPN_UID here. (b/176542831)
        exemptUids[0] = VPN_UID;
        exemptUids[1] = nai.networkCapabilities.getOwnerUid();
        UidRangeParcel[] ranges = toUidRangeStableParcels(uidRanges);

        maybeCloseSockets(nai, ranges, exemptUids);
        try {
            if (add) {
                mNetd.networkAddUidRangesParcel(new NativeUidRangeConfig(
                        nai.network.netId, ranges, PREFERENCE_ORDER_VPN));
            } else {
                mNetd.networkRemoveUidRangesParcel(new NativeUidRangeConfig(
                        nai.network.netId, ranges, PREFERENCE_ORDER_VPN));
            }
        } catch (Exception e) {
            loge(&quot;Exception while &quot; + (add ? &quot;adding&quot; : &quot;removing&quot;) + &quot; uid ranges &quot; + uidRanges +
                    &quot; on netId &quot; + nai.network.netId + &quot;. &quot; + e);
        }
        maybeCloseSockets(nai, ranges, exemptUids);
    }
    
        private void maybeCloseSockets(NetworkAgentInfo nai, UidRangeParcel[] ranges,
            int[] exemptUids) {
        if (nai.isVPN() &amp;&amp; !nai.networkAgentConfig.allowBypass) {
            try {
                mNetd.socketDestroy(ranges, exemptUids);
            } catch (Exception e) {
                loge(&quot;Exception in socket destroy: &quot;, e);
            }
        }
    }
    
    protected ConnectivityService(Context context, IDnsResolver dnsresolver,
            IpConnectivityLog logger, INetd netd, Dependencies deps) {
            mNetd = netd;
            
    public ConnectivityService(Context context) {
        this(context, getDnsResolver(context), new IpConnectivityLog(),
                INetd.Stub.asInterface((IBinder) context.getSystemService(Context.NETD_SERVICE)),
                new Dependencies());

    }
    
</code></pre>
<p><a href="https://cs.android.com/android/platform/superproject/+/master:out/soong/.intermediates/frameworks/libs/net/common/netd/netd_aidl_interface-V14-java-source/gen/android/net/INetd.java;l=6;drc=f42a611faa92d6bff1dfeade9b4e9775e7d15b9f;bpv=1;bpt=1">out/soong/.intermediates/frameworks/libs/net/common/netd/netd_aidl_interface-V14-java-source/gen/android/net/INetd.java</a></p>
<pre><code>  /**
     * Adds or removes one rule for each supplied UID range to prohibit all network activity outside
     * of secure VPN.
     * 
     * When a UID is covered by one of these rules, traffic sent through any socket that is not
     * protected or explicitly overriden by the system will be rejected. The kernel will respond
     * with an ICMP prohibit message.
     * 
     * Initially, there are no such rules. Any rules that are added will only last until the next
     * restart of netd or the device.
     * 
     * @param add {@code true} if the specified UID ranges should be denied access to any network
     *        which is not secure VPN by adding rules, {@code false} to remove existing rules.
     * @param uidRanges a set of non-overlapping, contiguous ranges of UIDs to which to apply or
     *        remove this restriction.
     *        &lt;p&gt; Added rules should not overlap with existing rules. Likewise, removed rules should
     *        each correspond to an existing rule.
     * 
     * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
     *         unix errno.
     */
    @Override public void networkRejectNonSecureVpn(boolean add, android.net.UidRangeParcel[] uidRanges) throws android.os.RemoteException
    {
    }
    /** Administratively closes sockets belonging to the specified UIDs. */
    @Override public void socketDestroy(android.net.UidRangeParcel[] uidRanges, int[] exemptUids) throws android.os.RemoteException
    {
</code></pre>
<p><a href="https://cs.android.com/android/platform/superproject/+/master:system/netd/server/NetdNativeService.cpp;l=389;drc=f42a611faa92d6bff1dfeade9b4e9775e7d15b9f;bpv=1;bpt=1">system/netd/server/NetdNativeService.cpp</a></p>
<pre><code>binder::Status NetdNativeService::socketDestroy(const std::vector&lt;UidRangeParcel&gt;&amp; uids,
                                                const std::vector&lt;int32_t&gt;&amp; skipUids) {
    ENFORCE_NETWORK_STACK_PERMISSIONS();

    SockDiag sd;
    if (!sd.open()) {
        return binder::Status::fromServiceSpecificError(EIO,
                String8(&quot;Could not open SOCK_DIAG socket&quot;));
    }

    UidRanges uidRanges(uids);
    int err = sd.destroySockets(uidRanges, std::set&lt;uid_t&gt;(skipUids.begin(), skipUids.end()),
                                true /* excludeLoopback */);
    if (err) {
        return binder::Status::fromServiceSpecificError(-err,
                String8::format(&quot;destroySockets: %s&quot;, strerror(-err)));
    }
    return binder::Status::ok();

binder::Status NetdNativeService::networkAddUidRanges(
        int32_t netId, const std::vector&lt;UidRangeParcel&gt;&amp; uidRangeArray) {
    // NetworkController::addUsersToNetwork is thread-safe.
    ENFORCE_NETWORK_STACK_PERMISSIONS();
    int ret = gCtls-&gt;netCtrl.addUsersToNetwork(netId, UidRanges(uidRangeArray),
                                               UidRanges::SUB_PRIORITY_HIGHEST);
    return statusFromErrcode(ret);
}
}
</code></pre>
<p><a href="https://cs.android.com/android/platform/superproject/+/master:system/netd/server/NetworkController.cpp;drc=f42a611faa92d6bff1dfeade9b4e9775e7d15b9f;bpv=1;bpt=1;l=624">system/netd/server/NetworkController.cpp</a></p>
<pre><code>int NetworkController::addUsersToNetwork(unsigned netId, const UidRanges&amp; uidRanges,
                                         int32_t subPriority) {
    ScopedWLock lock(mRWLock);
    Network* network = getNetworkLocked(netId);
    if (int ret = isWrongNetworkForUidRanges(netId, network)) {
        return ret;
    }
    return network-&gt;addUsers(uidRanges, subPriority);
}
</code></pre>
<p><a href="https://cs.android.com/android/platform/superproject/+/master:system/netd/server/SockDiag.h;l=89;drc=f42a611faa92d6bff1dfeade9b4e9775e7d15b9f;bpv=1;bpt=1">system/netd/server/SockDiag.h</a></p>
<pre><code>class SockDiag {
  // Destroys all &quot;live&quot; (CONNECTED, SYN_SENT, SYN_RECV) TCP sockets for the given UID ranges.
    int destroySockets(const UidRanges&amp; uidRanges, const std::set&lt;uid_t&gt;&amp; skipUids,
                       bool excludeLoopback);
</code></pre>
<h1 id="a-idprotecta-protect%E7%9A%84%E5%AE%9E%E7%8E%B0"><a id="protect"></a> protect&#x7684;&#x5B9E;&#x73B0;</h1>
<p>&#x8981;&#x8BA9;&#x6307;&#x5B9A;socket&#x7ED5;&#x8FC7;vpn&#xFF0C;&#x9700;&#x8981;&#x901A;&#x77E5;fwmark&#x670D;&#x52A1;&#x5668;&#x3002;</p>
<h4 id="vpnservice">VPNService</h4>
<p><a href="https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/net/VpnService.java;l=260">frameworks/base/core/java/android/net/VpnService.java</a></p>
<pre><code>    /**
     * Protect a socket from VPN connections. After protecting, data sent
     * through this socket will go directly to the underlying network,
     * so its traffic will not be forwarded through the VPN.
     * This method is useful if some connections need to be kept
     * outside of VPN. For example, a VPN tunnel should protect itself if its
     * destination is covered by VPN routes. Otherwise its outgoing packets
     * will be sent back to the VPN interface and cause an infinite loop. This
     * method will fail if the application is not prepared or is revoked.
     *
     * &lt;p class=&quot;note&quot;&gt;The socket is NOT closed by this method.
     *
     * @return {@code true} on success.
     */
    public boolean protect(int socket) {
        return NetworkUtilsInternal.protectFromVpn(socket);
    }
</code></pre>
<p><a href="https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/com/android/internal/net/NetworkUtilsInternal.java;drc=f42a611faa92d6bff1dfeade9b4e9775e7d15b9f;l=52">frameworks/base/core/java/com/android/internal/net/NetworkUtilsInternal.java</a></p>
<pre><code>  /**
     * Protect {@code socketfd} from VPN connections.  After protecting, data sent through
     * this socket will go directly to the underlying network, so its traffic will not be
     * forwarded through the VPN.
     */
    public static native boolean protectFromVpn(int socketfd);
</code></pre>
<p><a href="https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/jni/com_android_internal_net_NetworkUtilsInternal.cpp;l=29;drc=f42a611faa92d6bff1dfeade9b4e9775e7d15b9f;bpv=1;bpt=1?q=protectFromVpn&amp;sq=&amp;ss=android%2Fplatform%2Fsuperproject">frameworks/base/core/jni/com_android_internal_net_NetworkUtilsInternal.cpp</a></p>
<pre><code>static jboolean android_net_utils_protectFromVpn(JNIEnv *env, jclass clazz, jint socket) {
    return (jboolean)!protectFromVpn(socket);
}

static jboolean android_net_utils_protectFromVpnWithFd(JNIEnv *env, jclass clazz, jobject javaFd) {
    return android_net_utils_protectFromVpn(env, clazz, AFileDescriptor_getFd(env, javaFd));
}

static const JNINativeMethod gNetworkUtilMethods[] = {
        {&quot;setAllowNetworkingForProcess&quot;, &quot;(Z)V&quot;,
         (void *)android_net_utils_setAllowNetworkingForProcess},
        {&quot;protectFromVpn&quot;, &quot;(I)Z&quot;, (void *)android_net_utils_protectFromVpn},
        {&quot;protectFromVpn&quot;, &quot;(Ljava/io/FileDescriptor;)Z&quot;,
         (void *)android_net_utils_protectFromVpnWithFd},
};

</code></pre>
<p><a href="https://cs.android.com/android/platform/superproject/+/master:system/netd/client/NetdClient.cpp;drc=f42a611faa92d6bff1dfeade9b4e9775e7d15b9f;bpv=1;bpt=1;l=490">system/netd/client/NetdClient.cpp</a></p>
<pre><code>extern &quot;C&quot; int protectFromVpn(int socketFd) {
    CHECK_SOCKET_IS_MARKABLE(socketFd);
    FwmarkCommand command = {FwmarkCommand::PROTECT_FROM_VPN, 0, 0, 0};
    return FwmarkClient().send(&amp;command, socketFd, nullptr);
}
</code></pre>
<h1 id="a-idlibca-libc"><a id="libc"></a> LIBC</h1>
<p>android&#x7684;libc&#x5B9E;&#x73B0;&#x662F;bionic&#xFF0C;&#x5728;&#x8FD9;&#x91CC;&#x5BF9;socket&#x7684;&#x57FA;&#x672C;Accept/Connect/Send&#x7B49;&#x64CD;&#x4F5C;&#x8FDB;&#x884C;&#x62E6;&#x622A;&#xFF0C;&#x4E0D;&#x662F;&#x76F4;&#x63A5;&#x8C03;&#x7528;syscall&#xFF0C;&#x800C;&#x662F;&#x6307;&#x5411;&#x4E86;libnetd_client.so&#x7684;&#x5B9E;&#x73B0;&#x3002;&#x4ECE;&#x800C;&#x5B9E;&#x73B0;&#x66F4;&#x590D;&#x6742;&#x7684;&#x529F;&#x80FD;&#x3002;</p>
<p>libc&#x7684;accept&#x51FD;&#x6570;&#x9ED8;&#x8BA4;&#x4F7F;&#x7528;__accept4(&#x5E94;&#x8BE5;&#x662F;syscall&#x7248;&#x672C;)&#xFF0C;&#x901A;&#x8FC7;&#x4F7F;&#x7528;Dispatch&#x7ED3;&#x6784;&#x4EE5;&#x5141;&#x8BB8;&#x8FDB;&#x884C;&#x66FF;&#x6362;&#x3002;</p>
<p><a href="https://cs.android.com/android/platform/superproject/+/master:bionic/libc/bionic/NetdClientDispatch.cpp;bpv=1;bpt=1">bionic/libc/bionic/NetdClientDispatch.cpp</a></p>
<pre><code>extern &quot;C&quot; __socketcall int __accept4(int, sockaddr*, socklen_t*, int);
extern &quot;C&quot; __socketcall int __connect(int, const sockaddr*, socklen_t);
...
extern &quot;C&quot; __socketcall int __socket(int, int, int);

__LIBC_HIDDEN__ NetdClientDispatch __netdClientDispatch __attribute__((aligned(32))) = {
    __accept4,
    __connect,
    ...
    __socket,
    ...
    
int accept4(int fd, sockaddr* addr, socklen_t* addr_length, int flags) {
  return FDTRACK_CREATE(__netdClientDispatch.accept4(fd, addr, addr_length, flags));
}

int connect(int fd, const sockaddr* addr, socklen_t addr_length) {
    return __netdClientDispatch.connect(fd, addr, addr_length);
}

...

int socket(int domain, int type, int protocol) {
  return FDTRACK_CREATE(__netdClientDispatch.socket(domain, type, protocol));
}
</code></pre>
<p>&#x542F;&#x52A8;&#x65F6;&#x8FDB;&#x884C;&#x521D;&#x59CB;&#x5316;&#xFF0C;&#x6307;&#x5411;&#x4E86;libnetd_client.so&#x7684;&#x5B9E;&#x73B0;&#x3002;</p>
<p><a href="https://cs.android.com/android/platform/superproject/+/master:bionic/libc/bionic/NetdClient.cpp;bpv=1;bpt=1">bionic/libc/bionic/NetdClient.cpp</a></p>
<pre><code>static void netdClientInitImpl() {
    // Prevent netd from looping back fwmarkd connections to itself. It would work, but it&apos;s
    // a deadlock hazard and unnecessary overhead for the resolver.
    if (getuid() == 0 &amp;&amp; strcmp(basename(getprogname()), &quot;netd&quot;) == 0) {
        async_safe_format_log(ANDROID_LOG_INFO, &quot;netdClient&quot;,
                              &quot;Skipping libnetd_client init since *we* are netd&quot;);
        return;
    }

    void* handle = dlopen(&quot;libnetd_client.so&quot;, RTLD_NOW);
    if (handle == nullptr) {
        // If the library is not available, it&apos;s not an error. We&apos;ll just use
        // default implementations of functions that it would&apos;ve overridden.
        return;
    }

    netdClientInitFunction(handle, &quot;netdClientInitAccept4&quot;, &amp;__netdClientDispatch.accept4);
    netdClientInitFunction(handle, &quot;netdClientInitConnect&quot;, &amp;__netdClientDispatch.connect);

...
    
static pthread_once_t netdClientInitOnce = PTHREAD_ONCE_INIT;

extern &quot;C&quot; __LIBC_HIDDEN__ void netdClientInit() {
    if (pthread_once(&amp;netdClientInitOnce, netdClientInitImpl)) {
        async_safe_format_log(ANDROID_LOG_ERROR, &quot;netdClient&quot;, &quot;Failed to initialize libnetd_client&quot;);
    }
}
</code></pre>
<h1 id="a-idnetdclienta-netdclient"><a id="netdclient"></a> NetdClient</h1>
<p>&#x66FF;&#x6362;&#x6807;&#x51C6;&#x5E93;accept&#x7684;&#x5B9E;&#x73B0;&#xFF0C;&#x8FDE;&#x63A5;Fwmark Server&#x7ED9;socket&#x8BBE;&#x7F6E;Fwmark&#x6807;&#x5FD7;, Fwmark&#x5305;&#x62EC;&#x4E86;NetId&#x7B49;&#x4FE1;&#x606F;&#x3002; &#x4F7F;&#x7528;union&#x7ED3;&#x6784;&#xFF0C;&#x65B9;&#x4FBF;&#x8BFB;&#x53D6;&#x539F;&#x503C;&#x548C;&#x6309;&#x5B57;&#x6BB5;&#x8986;&#x76D6;&#x3002;</p>
<p><a href="https://cs.android.com/android/platform/superproject/+/master:system/netd/include/Fwmark.h;drc=bbd7c97afa0022069315446070727afed2b62ba0;l=25">system/netd/include/Fwmark.h</a></p>
<pre><code>union Fwmark {
    uint32_t intValue;
    struct {
        unsigned netId          : 16;
        bool explicitlySelected :  1;
        bool protectedFromVpn   :  1;
        Permission permission   :  2;
        bool uidBillingDone     :  1;
    };
...
};
static const unsigned FWMARK_NET_ID_MASK = 0xffff;
static_assert(sizeof(Fwmark) == sizeof(uint32_t), &quot;The entire fwmark must fit into 32 bits&quot;);
</code></pre>
<p><a href="https://cs.android.com/android/platform/superproject/+/master:system/netd/client/NetdClient.cpp;drc=9f75a97cc42ff34708ea59ba7904164739deca91;bpv=1;bpt=1;l=405">system/netd/client/NetdClient.cpp</a></p>
<pre><code>
// accept() just calls accept4(..., 0), so there&apos;s no need to handle accept() separately.
extern &quot;C&quot; void netdClientInitAccept4(Accept4FunctionType* function) {
    HOOK_ON_FUNC(function, libcAccept4, netdClientAccept4);
}

...

#define HOOK_ON_FUNC(remoteFunc, nativeFunc, localFunc) \
    do {                                                \
        if ((remoteFunc) &amp;&amp; *(remoteFunc)) {            \
            (nativeFunc) = *(remoteFunc);               \
            *(remoteFunc) = (localFunc);                \
        }                                               \
    } while (false)

...

// These variables are only modified at startup (when libc.so is loaded) and never afterwards, so
// it&apos;s okay that they are read later at runtime without a lock.
Accept4FunctionType libcAccept4 = nullptr;

...

int netdClientAccept4(int sockfd, sockaddr* addr, socklen_t* addrlen, int flags) {
    int acceptedSocket = libcAccept4(sockfd, addr, addrlen, flags);
    if (acceptedSocket == -1) {
        return -1;
    }
    int family;
    if (addr) {
        family = addr-&gt;sa_family;
    } else {
        socklen_t familyLen = sizeof(family);
        if (getsockopt(acceptedSocket, SOL_SOCKET, SO_DOMAIN, &amp;family, &amp;familyLen) == -1) {
            return closeFdAndSetErrno(acceptedSocket, -errno);
        }
    }
    if (FwmarkClient::shouldSetFwmark(family)) {
        FwmarkCommand command = {FwmarkCommand::ON_ACCEPT, 0, 0, 0};
        if (int error = FwmarkClient().send(&amp;command, acceptedSocket, nullptr)) {
            return closeFdAndSetErrno(acceptedSocket, error);
        }
    }
    return acceptedSocket;
}

int netdClientConnect(int sockfd, const sockaddr* addr, socklen_t addrlen) {
    const bool shouldSetFwmark = shouldMarkSocket(sockfd, addr);
    if (shouldSetFwmark) {
        FwmarkCommand command = {FwmarkCommand::ON_CONNECT, 0, 0, 0};
        int error;
        if (redirectSocketCallsIsTrue()) {
            FwmarkConnectInfo connectInfo(0, 0, addr);
            error = FwmarkClient().send(&amp;command, sockfd, &amp;connectInfo);
        } else {
            error = FwmarkClient().send(&amp;command, sockfd, nullptr);
        }


    ...

</code></pre>
<h1 id="a-idnetda-netd-server"><a id="netd"></a> Netd Server</h1>
<p>&#x63D0;&#x4F9B;INetd&#x63A5;&#x53E3;&#x7684;&#x5B9E;&#x73B0;&#xFF08;NetdNativeService&#xFF09;&#xFF0C;app&#x53EF;&#x4EE5;&#x8FDC;&#x7A0B;&#x8C03;&#x7528;&#x5B9E;&#x73B0;&#x5F88;&#x591A;&#x7F51;&#x7EDC;&#x76F8;&#x5173;&#x7684;&#x64CD;&#x4F5C;&#x3002;&#x8D1F;&#x8D23;&#x542F;&#x52A8;&#x5404;&#x79CD;&#x5E95;&#x5C42;&#x670D;&#x52A1;&#xFF08;&#x6BD4;&#x5982;fwmark server&#xFF0C;mdns&#xFF0C;dnsproxy&#xFF09;&#xFF0C;&#x4EE5;&#x4F9B;framework&#x8C03;&#x7528;&#x3002;</p>
<p>Linux&#x5185;&#x6838;&#x4E4B;&#x4E0A;&#x7684;&#x7F51;&#x7EDC;&#x7BA1;&#x7406;&#xFF0C;&#x7531;netd&#x8FDB;&#x7A0B;&#x63D0;&#x4F9B;&#x3002;&#x7528;&#x6237;&#x6001;&#x7684;&#x7F51;&#x7EDC;&#x7BA1;&#x7406;&#x8FDB;&#x7A0B;/&#x5DE5;&#x5177;&#xFF0C;&#x5728;&#x4E0D;&#x540C;&#x7684;linux&#x53D1;&#x884C;&#x7248;&#x4E2D;&#x672C;&#x5C31;&#x4E0D;&#x540C;&#xFF0C;&#x7531;&#x4E0D;&#x540C;&#x7684;&#x5E94;&#x7528;&#x5171;&#x540C;&#x6784;&#x6210;&#x3002;netd&#x5C31;&#x662F;android&#x7684;&#x5B9E;&#x73B0;&#xFF0C;&#x4E00;&#x4E2A;&#x8FDB;&#x7A0B;&#x5168;&#x90FD;&#x5305;&#x62EC;&#x4E86;&#x3002;</p>
<h4 id="fwmark-server">Fwmark Server</h4>
<p>&#x81EA;&#x52A8;&#x9009;&#x62E9;netId&#xFF0C;&#x4F7F;&#x7528;SO_MARK&#x8FDB;&#x884C;&#x6807;&#x5FD7;&#xFF0C;&#x7528;&#x4E8E;&#x8DEF;&#x7531;&#x8BC6;&#x522B;&#x3002;</p>
<p><a href="https://cs.android.com/android/platform/superproject/+/master:system/netd/server/FwmarkServer.cpp">system/netd/server/FwmarkServer.cpp</a></p>
<pre><code>int FwmarkServer::processClient(SocketClient* client, int* socketFd) {
...
  switch (command.cmdId) {
        case FwmarkCommand::ON_CONNECT: {
            // Called before a socket connect() happens. Set an appropriate NetId into the fwmark so
            // that the socket routes consistently over that network. Do this even if the socket
            // already has a NetId, so that calling connect() multiple times still works.
            ...
            if (!fwmark.explicitlySelected) {
                if (!fwmark.protectedFromVpn) {
                    fwmark.netId = mNetworkController-&gt;getNetworkForConnect(client-&gt;getUid());
                } else if (!mNetworkController-&gt;isVirtualNetwork(fwmark.netId)) {
                    fwmark.netId = mNetworkController-&gt;getDefaultNetwork();
                }
            }
            break;
            ...
            
  if (setsockopt(*socketFd, SOL_SOCKET, SO_MARK, &amp;fwmark.intValue,
                   sizeof(fwmark.intValue)) == -1) {
        return -errno;
    }

    return 0;
...            
</code></pre>
<h4 id="networkcontroller">NetworkController</h4>
<p>&#x7ED3;&#x679C;&#x6700;&#x540E;&#x90FD;&#x8F6C;&#x4E3A;&#x5BF9;linux&#x7F51;&#x7EDC;&#x7684;&#x64CD;&#x4F5C;&#xFF0C;&#x5C31;&#x662F;ip rule&#x548C;ip route&#x7684;&#x64CD;&#x4F5C;&#xFF0C;&#x4E0D;&#x540C;&#x7684;netid&#x5BF9;&#x5E94;&#x4E0D;&#x540C;&#x7684;table&#xFF0C;&#x800C;fwmark&#x5219;&#x7528;&#x4E8E;rule&#x7684;&#x89C4;&#x5219;&#x5339;&#x914D;&#x3002;</p>
<p><a href="https://cs.android.com/android/platform/superproject/+/master:system/netd/server/NetworkController.h;bpv=0;bpt=1">system/netd/server/NetworkController.h</a></p>
<pre><code>/*
 * Keeps track of default, per-pid, and per-uid-range network selection, as
 * well as the mark associated with each network. Networks are identified
 * by netid. In all set* commands netid == 0 means &quot;unspecified&quot; and is
 * equivalent to clearing the mapping.
 */
class NetworkController {
    ...
    unsigned getDefaultNetwork() const;
    [[nodiscard]] int setDefaultNetwork(unsigned netId);

    unsigned getNetworkForUser(uid_t uid) const;
    unsigned getNetworkForConnect(uid_t uid) const;
    
    ...
    
    // |nexthop| can be NULL (to indicate a directly-connected route), &quot;unreachable&quot; (to indicate a
    // route that&apos;s blocked), &quot;throw&quot; (to indicate the lack of a match), or a regular IP address.
    //
    // Routes are added to tables determined by the interface, so only |interface| is actually used.
    // |netId| is given only to sanity check that the interface has the correct netId.
    [[nodiscard]] int addRoute(unsigned netId, const char* interface, const char* destination,
                               const char* nexthop, bool legacy, uid_t uid, int mtu);
                               
    ...
    

</code></pre>
<p><a href="https://cs.android.com/android/platform/superproject/+/master:system/netd/server/NetworkController.cpp;bpv=0;bpt=1">system/netd/server/NetworkController.cpp</a></p>
<pre><code>int NetworkController::addRoute(unsigned netId, const char* interface, const char* destination,
                                const char* nexthop, bool legacy, uid_t uid, int mtu) {
    return modifyRoute(netId, interface, destination, nexthop, ROUTE_ADD, legacy, uid, mtu);
}
int NetworkController::modifyRoute(unsigned netId, const char* interface, const char* destination,
                                   const char* nexthop, enum RouteOperation op, bool legacy,
                                   uid_t uid, int mtu) {
  ...
  unsigned existingNetId = getNetworkForInterfaceLocked(interface);
  ...
  switch (op) {  
        case ROUTE_ADD:
            return RouteController::addRoute(interface, destination, nexthop, tableType, mtu,
                                             0 /* priority */);
</code></pre>
<p><a href="https://cs.android.com/android/platform/superproject/+/master:system/netd/server/RouteController.cpp;drc=bbd7c97afa0022069315446070727afed2b62ba0;bpv=0;bpt=1;l=1466">system/netd/server/RouteController.cpp</a></p>
<pre><code>int RouteController::addRoute(const char* interface, const char* destination, const char* nexthop,
                              TableType tableType, int mtu, int priority) {
    if (int ret = modifyRoute(RTM_NEWROUTE, NETLINK_ROUTE_CREATE_FLAGS, interface, destination,
                              nexthop, tableType, mtu, priority, false /* isLocal */)) {
        return ret;
    }
    
// Adds or removes an IPv4 or IPv6 route to the specified table.
// Returns 0 on success or negative errno on failure.
int RouteController::modifyRoute(uint16_t action, uint16_t flags, const char* interface,
                                 const char* destination, const char* nexthop, TableType tableType,
                                 int mtu, int priority, bool isLocal) {
    uint32_t table;
    switch (tableType) {
        case RouteController::INTERFACE: {
            table = getRouteTableForInterface(interface, isLocal);
    
    int ret = modifyIpRoute(action, flags, table, interface, destination, nexthop, mtu, priority);
 
int modifyIpRoute(uint16_t action, uint16_t flags, uint32_t table, const char* interface,
                  const char* destination, const char* nexthop, uint32_t mtu, uint32_t priority) {
                  
  int ret = sendNetlinkRequest(action, flags, iov, ARRAY_SIZE(iov), nullptr);
</code></pre>
<p>&#x6700;&#x540E;&#xFF0C;&#x6211;&#x8FD8;&#x662F;&#x6CA1;&#x80FD;&#x7406;&#x89E3;&#x4E3A;&#x4EC0;&#x4E48;protect&#x4E0D;&#x751F;&#x6548;&#xFF0C;&#x6CA1;&#x9053;&#x7406;&#x554A;&#x3002;</p>
<!--kg-card-end: markdown--><blockquote><strong>2024.10.10 Update: &#xA0;minivtun-android&#x5DF2;&#x7ECF;&#x53EF;&#x4EE5;&#x4F7F;&#x7528;protect&#x3002;</strong></blockquote><blockquote><strong>2024.12.08 Update: &#x4E0D;&#x80FD;&#x4F7F;&#x7528;protect&#x7684;&#x539F;&#x56E0;&#x7EC8;&#x4E8E;&#x627E;&#x5230;&#x4E86;&#xFF01;&#x56E0;&#x4E3A;&#x6211;&#x5728;&#x8C03;&#x7528;vpnservice&#x7684;protect()&#x4E4B;&#x524D;&#xFF0C;&#x8C03;&#x7528;&#x4E86;udp&#x7684;connect()&#x65B9;&#x6CD5;&#x3002;&#x4E00;&#x65E6;&#x8C03;&#x7528;connect&#x4E4B;&#x540E;&#xFF0C;linux&#x5185;&#x6838;&#x5C31;&#x628A;&#x8DEF;&#x7531;&#x67E5;&#x8BE2;&#x5B8C;&#x6BD5;&#x4E86;&#xFF0C;&#x4E4B;&#x540E;&#x518D;&#x901A;&#x8FC7;protect&#x8BBE;&#x7F6E;fwmark&#x5DF2;&#x7ECF;&#x665A;&#x4E86;&#xFF0C;&#x5185;&#x6838;&#x4E0D;&#x4F1A;&#x518D;&#x67E5;&#x8BE2;&#x8DEF;&#x7531;&#x4E86;&#xFF01;</strong></blockquote><p><strong>&#x4EE5;&#x4E0B;&#x662F;Claude-3.5-Sonnet&#x751F;&#x6210;&#x7684;&#x89E3;&#x91CA;</strong><br></p><p><strong>Understanding the Mechanism</strong></p><p>To understand this issue, we need to look at three key components:</p><p><strong>UDP Connect Operation</strong></p><ul><li>When you call connect() on a UDP socket, the kernel performs a route lookup</li><li>This routing decision gets cached for subsequent send() operations</li><li>The route is determined based on current socket attributes, including fwmark</li></ul><p><strong>VpnService.protect()</strong></p><ul><li>Under the hood, protect() sets a special fwmark on the socket</li><li>This fwmark tells the kernel to bypass VPN routing</li><li>The fwmark is used during route lookup decisions</li></ul><p><strong>Kernel Route Caching</strong></p><ul><li>Once a route is cached by connect(), it stays until the socket is disconnected</li><li>Changing fwmark after connect() won&apos;t trigger a new route lookup</li><li>The cached route continues to be used regardless of later fwmark changes</li></ul>]]></content:encoded></item><item><title><![CDATA[支持内网穿透的VPN应用]]></title><description><![CDATA[<p>&#x5728;&#x4EE5;&#x524D;&#x5BBD;&#x5E26;&#x8FD0;&#x8425;&#x5546;&#x63D0;&#x4F9B;&#x516C;&#x7F51;IP&#x7684;&#x65F6;&#x5019;&#xFF0C;&#x6211;&#x4E00;&#x76F4;&#x4F7F;&#x7528;&#x7684;&#x662F;IPSec&#x8BBF;&#x95EE;&#x5185;&#x7F51;&#x3002;&#x540E;&#x6765;&#x6CA1;&#x6709;&#x4E86;&#x516C;&#x7F51;IP&#xFF0C;&#x53EA;&#x80FD;&#x4F7F;&#x7528;<a href="https://blog.optman.net/wgsd-wireguard-ipv6/">Wireguard+Wgsd</a>&#x5728;&#x4E24;&#x7AEF;&#x8DEF;&#x7531;</p>]]></description><link>https://blog.optman.net/minivtun-android/</link><guid isPermaLink="false">63be6b7ed094470001c6eaef</guid><category><![CDATA[Network]]></category><category><![CDATA[rust]]></category><dc:creator><![CDATA[optman]]></dc:creator><pubDate>Wed, 11 Jan 2023 09:06:32 GMT</pubDate><content:encoded><![CDATA[<p>&#x5728;&#x4EE5;&#x524D;&#x5BBD;&#x5E26;&#x8FD0;&#x8425;&#x5546;&#x63D0;&#x4F9B;&#x516C;&#x7F51;IP&#x7684;&#x65F6;&#x5019;&#xFF0C;&#x6211;&#x4E00;&#x76F4;&#x4F7F;&#x7528;&#x7684;&#x662F;IPSec&#x8BBF;&#x95EE;&#x5185;&#x7F51;&#x3002;&#x540E;&#x6765;&#x6CA1;&#x6709;&#x4E86;&#x516C;&#x7F51;IP&#xFF0C;&#x53EA;&#x80FD;&#x4F7F;&#x7528;<a href="https://blog.optman.net/wgsd-wireguard-ipv6/">Wireguard+Wgsd</a>&#x5728;&#x4E24;&#x7AEF;&#x8DEF;&#x7531;&#x5668;&#x4E0A;&#x5B8C;&#x6210;&#x7A7F;&#x900F;&#x3002;&#x624B;&#x673A;&#x5982;&#x679C;&#x6CA1;&#x6709;&#x8FDE;&#x63A5;&#x6307;&#x5B9A;&#x8DEF;&#x7531;&#x5668;&#xFF0C;&#x5C31;&#x53EA;&#x80FD;&#x4F7F;&#x7528;&#x56FD;&#x5185;VPS&#x4E2D;&#x8F6C;IPSec&#x6570;&#x636E;&#x3002;&#x4F46;&#x4E0D;&#x80FD;&#x4ECE;&#x624B;&#x673A;&#x76F4;&#x63A5;&#x8BBF;&#x95EE;&#x5185;&#x7F51;&#x4E00;&#x76F4;&#x662F;&#x4E2A;&#x9057;&#x61BE;&#xFF0C;&#x56E0;&#x4E3A;&#x56FD;&#x5185;VPS&#x7684;&#x5E26;&#x5BBD;&#x53EF;&#x4E0D;&#x4FBF;&#x5B9C;&#x3002;</p><p>&#x5B9E;&#x9645;&#x4E0A;&#xFF0C;&#x9664;&#x4E86;WireGuard&#xFF0C;&#x6211;&#x8FD8;&#x4E00;&#x76F4;&#x8FD8;&#x540C;&#x65F6;&#x5728;&#x4F7F;&#x7528;Minivtun&#xFF0C;&#x751A;&#x81F3;&#x8FD8;&#x5199;&#x4E86;&#x4E00;&#x4E2A;Rust&#x7684;<a href="https://github.com/optman/minivtun-rs">&#x514B;&#x9686;&#x7248;&#x672C;</a>&#x3002;WireGuard&#x7684;&#x52A3;&#x52BF;&#x662F;&#x6570;&#x636E;&#x5305;&#x6709;&#x660E;&#x663E;&#x7684;&#x7279;&#x5F81;&#x5F88;&#x5BB9;&#x6613;&#x88AB;&#x8BC6;&#x522B;&#x548C;&#x5C4F;&#x853D;&#xFF0C;Minivtun&#x5219;&#x5B8C;&#x5168;&#x6CA1;&#x6709;&#x4EFB;&#x4F55;&#x7279;&#x5F81; &#x3002;Minivtun&#x7684;&#x4EE3;&#x7801;&#x8FD8;&#x975E;&#x5E38;&#x7B80;&#x5355;&#xFF0C;&#x5F88;&#x5BB9;&#x6613;&#x4FEE;&#x6539;&#x3002;&#x5728;Rust&#x7248;&#x672C;&#x91CC;&#xFF0C;&#x6211;&#x52A0;&#x5165;&#x4E86;&#x539F;&#x59CB;&#x7248;&#x672C;&#x91CC;&#x6CA1;&#x6709;&#x7684;&#x4E24;&#x4E2A;&#x529F;&#x80FD;&#xFF0C;fwmark&#x548C;rebind&#x3002;&#x524D;&#x8005;&#x4FBF;&#x4E8E;&#x8BBE;&#x7F6E;&#x8DEF;&#x7531;&#x89C4;&#x5219;&#xFF08;&#x53C2;&#x7167;wireguard&#xFF09;&#xFF0C;&#x7279;&#x522B;&#x662F;&#x9ED8;&#x8BA4;&#x8DEF;&#x7531;&#x3002;&#x540E;&#x8005;&#x5219;&#x5728;&#x65AD;&#x8FDE;&#x65F6;&#xFF0C;&#x81EA;&#x52A8;&#x53D8;&#x6362;&#x7AEF;&#x53E3;&#xFF0C;&#x8FD9;&#x6837;&#x5C31;&#x7A33;&#x5B9A;&#x5F88;&#x591A;&#x3002;</p><p>&#x7136;&#x800C;&#xFF0C;&#x867D;&#x7136;WireGuard&#x53EF;&#x4EE5;&#x501F;&#x52A9;WireGuard-Wgsd&#x8FDB;&#x884C;&#x5185;&#x7F51;&#x7A7F;&#x900F;&#xFF0C;Minivtun&#x5374;&#x505A;&#x4E0D;&#x5230;&#x3002;&#x4E5F;&#x4E0D;&#x662F;&#x505A;&#x4E0D;&#x5230;&#xFF0C;&#x5728;&#x53BB;&#x5E74;&#x4E0A;&#x534A;&#x5E74;&#x6709;&#x611F;&#x4E8E;libp2p&#x7684;<a href="https://blog.optman.net/go-libp2p-holepunching/">&#x5206;&#x5E03;&#x5F0F;&#x6253;&#x5B54;</a>&#x529F;&#x80FD;&#x592A;&#x5F31;&#x9E21;&#x7684;&#x65F6;&#x5019;&#xFF0C;&#x6211;&#x66FE;&#x7ECF;&#x641E;&#x4E86;&#x4E00;&#x4E2A;&#x7B80;&#x5355;&#x7684;&#x6253;&#x5B54;&#x5E93;<a href="https://blog.optman.net/hole-punching-rust/">Rndz</a>&#xFF0C;&#x5E76;&#x628A;Minivtun&#x8FDB;&#x884C;&#x4E86;&#x6539;&#x9020;&#xFF0C;&#x53EF;&#x4EE5;&#x505A;&#x5230;&#x5185;&#x7F51;&#x7A7F;&#x900F;&#x4E86;&#x3002;&#x4F46;&#x56E0;&#x4E3A;&#x5DF2;&#x7ECF;&#x6709;&#x4E86;WireGuard-Wgsd&#xFF0C;&#x8FD9;&#x4E2A;&#x53EF;&#x4EE5;&#x7A7F;&#x900F;&#x7684;Minivtun&#x663E;&#x5F97;&#x5F88;&#x9E21;&#x808B;&#xFF0C;&#x6CA1;&#x7528;&#x4E0A;&#x3002;</p><p>&#x6211;&#x4E00;&#x76F4;&#x60F3;&#x8981;&#x7684;&#x662F;&#x53EF;&#x4EE5;&#x4ECE;&#x624B;&#x673A;&#x8BBF;&#x95EE;&#x5185;&#x7F51;&#x7684;&#x529F;&#x80FD;&#xFF0C;&#x7279;&#x522B;&#x662F;&#x5728;&#x4F7F;&#x7528;&#x79FB;&#x52A8;&#x7F51;&#x7EDC;&#x7684;&#x65F6;&#x5019;&#x3002;&#x60F3;&#x6CD5;&#x7531;&#x6765;&#x5DF2;&#x4E45;&#xFF0C;&#x7EC8;&#x4E8E;&#x5728;&#x4E0A;&#x4E2A;&#x6708;&#x52A8;&#x624B;&#x5E72;&#x4E86;&#x3002;App&#x662F;&#x4ECE;Android SDK&#x7684;ToyVPN&#x7684;&#x4F8B;&#x5B50;&#x7B80;&#x5355;&#x6539;&#x9020;&#x7684;&#xFF0C;&#x4F7F;&#x7528;JNI&#x8C03;&#x7528;minivtun-rs&#x7684;lib&#x3002;&#x76EE;&#x524D;&#x5DF2;&#x7ECF;&#x5728;&#x624B;&#x673A;&#x7A33;&#x5B9A;&#x8DD1;&#x4E86;&#x4E24;&#x5929;&#xFF0C;&#x53EF;&#x4EE5;&#x5728;wifi&#x548C;&#x6570;&#x636E;&#x4E4B;&#x95F4;&#x81EA;&#x7531;&#x5207;&#x6362;&#xFF0C;&#x8017;&#x7535;&#x91CF;&#x4E5F;&#x5F88;&#x4F4E;&#xFF0C;&#x53EF;&#x4EE5;&#x4E00;&#x76F4;&#x5F00;&#x7740;&#x3002;&#x867D;&#x7136;&#x4EE3;&#x7801;&#x5F88;&#x7CD9;&#xFF0C;&#x754C;&#x9762;&#x4E5F;&#x975E;&#x5E38;&#x7B80;&#x964B;&#xFF0C;&#x4F46;&#x662F;&#x6682;&#x65F6;&#x591F;&#x7528;&#x4E86;&#xFF0C;&#x5475;&#x5475;&#x3002;</p><p>&#x4EE3;&#x7801;&#x5728;&#x8FD9;&#x91CC;<a href="https://github.com/optman/minivtun-android">1</a>&#xFF0C;<a href="https://github.com/optman/minivtun-rs/tree/holepunch">2</a>&#xFF0C;&#x4F9B;&#x6298;&#x817E;&#x3002;</p><p> </p><p></p><p></p>]]></content:encoded></item></channel></rss>