AI・機械学習
Show HN: SwiftでLangGraphを構築しました
Show HN: I Built LangGraph for Swift (github.com)
要約
Swarmは、Swiftでエージェントとマルチエージェントワークフローを構築するためのフレームワークです。Swiftのコンカレンシー安全性を活用し、コンパイル時の型安全なツール呼び出し、クラッシュからの復旧、多様な基盤モデルとの連携を可能にします。宣言的なエージェント仕様やスキル定義もサポートしており、iOS/macOS開発者にとってAIエージェント構築の強力な選択肢となります。
全文翻訳
Swiftでエージェントとマルチエージェントワークフローを構築するためのフレームワークです。
let result = try await Workflow() .step(researchAgent) .step(writerAgent) .run("Summarize the latest WWDC session on Swift concurrency.")
2つのエージェント、1つのパイプライン、クラッシュリカバリとSwiftコンカレンシー安全性を備えたDAGにコンパイルされます。
.package(url: "https://github.com/christopherkarani/Swarm.git", from: "0.6.0") をインストールします。
クイックスタート
import Swarm
// @Tool マクロはコンパイル時にJSONスキーマを生成します
@Tool("Looks up the current stock price")
struct PriceTool {
@Parameter("Ticker symbol")
var ticker: String
func execute() async throws -> String {
"182.50"
}
}
// ラベルなしの指示でエージェントを作成し、後続の @ToolBuilder クロージャでツールを使用します
let agent = try Agent("Answer finance questions using real data.", configuration: .init(name: "Analyst"), inferenceProvider: .anthropic(key: "{ENV}")) {
PriceTool()
CalculatorTool()
}
let result = try await agent.run("What is AAPL trading at?")
print(result.output) // "Apple (AAPL) is currently trading at $182.50."
これは動作するエージェントで、型安全なツール呼び出しが可能です。
Swarmは宣言的なエージェント仕様と再利用可能なスキル用のAGENTS.mdおよびSKILL.mdもサポートしています。完全なワークスペースレイアウトについては、Getting Startedガイドを参照してください。
Swarmを選ぶ理由
Swiftコンカレンシーは表面の一部です。Swift 6.2 StrictConcurrencyがパッケージ全体で有効になっています。
ツールは型安全性を保ちます。
@Tool マクロはSwift構造体からJSONスキーマを生成します。
ワークフローはクラッシュから回復できます。
永続的なワークフローチェックポインティングにより、明示的なチェックポイントIDから再開できます。
クラウドおよびオンデバイスモデルは同じ抽象化を使用します。
Foundation Models, Anthropic, OpenAI, Ollama, Gemini, MiniMax, OpenRouter, MLXはすべて同じ形状に適合します。
すべてSwiftで書かれています。
AsyncThrowingStream, アクター, 結果ビルダー, マクロはここでファーストクラスです。
例
機能マトリックスはSwarmに、1つの決定論的なマトリックスで安定したサーフェスエリアを行使するインリポジトリの機能ショーケースを現在出荷しています。
エージェントとツール
会話のストリーミングとセッションの永続化
シーケンシャル、パラレル、ルーティング、リピートアンティルワークフロー
ハンドオフ
メモリ
オンデバイスワークスペースのロード
ガードレール
レジリエンスヘルパー
永続的なチェックポイントと再開
オブザーバビリティ
MCPディスカバリとツールブリッジング
プロバイダー選択
ローカルで実行:
swift run SwarmCapabilityShowcase list
swift run SwarmCapabilityShowcase matrix
swift run SwarmCapabilityShowcase run handoff
swift run SwarmCapabilityShowcase smoke
決定論的なマトリックスはCIセーフです。ライブプロバイダーのスモークカバレッジは、環境変数を通じてオプトインです。シナリオカタログとスモークモードの詳細については、docs/guide/capability-showcase.mdを参照してください。
オプションデモ
デモ実行可能ファイルはオプトインなので、デフォルトのライブラリグラフはフレームワーク製品に焦点を当てています。
SWARM_INCLUDE_DEMO=1 swift build
SWARM_INCLUDE_DEMO=1 swift run SwarmDemo
SWARM_INCLUDE_DEMO=1 swift run SwarmMCPServerDemo
マルチエージェントパイプライン
let researcher = try Agent("Research the topic and extract key facts.", inferenceProvider: .anthropic(key: "sk-...")) {
WebSearchTool()
}
let writer = try Agent("Write a concise summary from the research.", inferenceProvider: .anthropic(key: "sk-..."))
let result = try await Workflow()
.step(researcher)
.step(writer)
.run("Latest advances in on-device ML")
各エージェントは独自のプロバイダーを解決します。
inferenceProvider: をエージェントごとに渡す(上記参照)、またはアプリ起動時に一度 await Swarm.configure(provider: .anthropic(apiKey: "...")) を呼び出して、指定されていないすべてのエージェントでデフォルトを共有します。
パラレルファンアウト
let result = try await Workflow()
.parallel([bullAgent, bearAgent, analystAgent], merge: .structured)
.run("Evaluate Apple's Q4 earnings.")
// 3つの視点が1つの出力にマージされます。
ダイナミックルーティング
let result = try await Workflow()
.route {
if input.contains("$") {
return mathAgent
}
if input.contains("weather") {
return weatherAgent
}
return generalAgent
}
.run("What is 15% of $240?")
ストリーミング
for try await event in agent.stream("Summarize the changelog.") {
switch event {
case .output(.token(let t)):
print(t, terminator: "")
case .tool(.completed(let call, _)):
print("\n[tool: \(call.toolName)]")
case .lifecycle(.completed(let r)):
print("\nDone in \(r.duration)")
case .lifecycle(.failed(let error)):
print("\nError: \(error)")
default:
break // 他のイベントには .output(.thinking(...)), .handoff(...), .observation(...), .lifecycle(.iterationStarted(...)) が含まれます。
}
}
その他の例
セマンティックメモリ
let agent = try Agent("You remember past conversations.", inferenceProvider: .anthropic(key: "sk-..."), memory: .vector(embeddingProvider: myEmbedder, similarityThreshold: 0.75)) {
// tools
}
ガードレール
let agent = try Agent("You are a helpful assistant.", inputGuardrails: [InputGuard.maxLength(5000), InputGuard.notEmpty()], outputGuardrails: [OutputGuard.maxLength(2000)])
クロージャツール
let reverse = FunctionTool(
name: "reverse",
description: "Reverses a string",
parameters: [
ToolParameter(name: "text", description: "Text to reverse", type: .string, isRequired: true)
]
) {
args in
let text = try args.require("text", as: String.self)
return .string(String(text.reversed()))
}
let agent = try Agent("Text utilities.", tools: [reverse])
クラッシュ耐性のあるワークフロー
let workflow = Workflow()
.step(monitor)
.durable.checkpoint(id: "monitor-v1", policy: .everyStep)
.durable.checkpointing(.fileSystem(directory: checkpointsURL))
let resumed = try await workflow.durable.execute("watch", resumeFrom: "monitor-v1")
プロバイダーの切り替え
// オンデバイス、プライベート、APIキー不要
let local = try Agent("Be helpful.", inferenceProvider: .foundationModels())
// クラウド
let cloud = try Agent("Be helpful.", inferenceProvider: .anthropic(key: k))
// または環境変数経由で実行時に切り替え
let modified = agent.environment(\.inferenceProvider, .ollama(model: "mistral"))
会話
let conversation = Conversation(with: agent)
let response1 = try await conversation.send("What's the weather?")
let response2 = try await conversation.send("And tomorrow?")
// コンテキストはメッセージの保持に役立ちます
for message in await conversation.messages {
print("\(message.role): \(message.text)")
}
Swarmと他フレームワークの比較
Swarm | LangChain | AutoGen
---|---|---
Language | Swift 6.2 | Python | Python
Data race safety | Compile-time | Runtime | Runtime
On-device LLM | Foundation Models | n/a | n/a
Execution model | Typed Workflow graph | Loop-based | Loop-based
Crash recovery | Checkpoints | n/a | Partial
Type-safe tools | @Tool macro (compile-time) | Decorators (runtime) | Runtime
Streaming | AsyncThrowingStream | Callbacks | Callbacks
iOS / macOS native | First-class | n/a | n/a
含まれるもの
Agents | Agent struct with @ToolBuilder trailing closure, AgentRuntime protocol
Workflows | Workflow: .step(), .parallel(), .route(), .repeatUntil(), .timeout()
Tools | @Tool macro, FunctionTool, @ToolBuilder, parallel execution
Memory | .conversation(maxMessages:), .vector(embeddingProvider:similarityThreshold:maxResults:), .slidingWindow(maxTokens:), .summary(configuration:summarizer:), .hybrid(configuration:summarizer:)
Guardrails | InputGuard.maxLength(), InputGuard.notEmpty(), InputGuard.custom(), OutputGuard.maxLength(), OutputGuard.custom()
Conversation | Conversation actor for stateful multi-turn dialogue
Resilience | 7 backoff strategies, circuit breaker, fallback chains, rate limiting
Observability | AgentObserver, Tracer, SwiftLogTracer, per-agent token metrics
MCP | Model Context Protocol client and server support
Providers | Foundation Models, Anthropic, OpenAI, Ollama, Gemini, MiniMax, OpenRouter, MLX via Conduit
Macros | @Tool, @Parameter, @Traceable, #Prompt
アーキテクチャ
┌─────────────────────────────────────────────────────────────┐
│ Your Application │
│ iOS 26+ · macOS 26+ · Linux (Ubuntu 22.04+) │
├─────────────────────────────────────────────────────────────┤
│ Workflow · Conversation · .run() · .stream() │
├─────────────────────────────────────────────────────────────┤
│ Agents Memory Tools │
│ Agent (struct) Memory factories @Tool macro │
│ AgentRuntime Conversation FunctionTool │
│ (dot-syntax) @ToolBuilder │
├─────────────────────