hefa-core

Crates.iohefa-core
lib.rshefa-core
version0.1.0
created_at2025-11-16 11:38:30.278459+00
updated_at2025-11-16 11:38:30.278459+00
descriptionRust LLM foundation: provider abstraction, tools, structured output, tracing.
homepagehttps://github.com/kitfactory/hefa-core
repositoryhttps://github.com/kitfactory/hefa-core
max_upload_size
id1935416
size150,675
Naruhide KITADA (kitfactory)

documentation

README

hefa-core

Rust 製 LLM 基盤ライブラリ。設計や詳細仕様は docs/ を参照してください。

開発手順

  1. .env.example をコピーして .env を作成し、必要な API キーを設定します。
  2. cargo fmt / cargo clippy / cargo test で品質を維持します。
  3. docs:
    • docs/hefa-core-spec.md 要件定義
    • docs/AGENTS.md Agent 層仕様
    • docs/PLAN.md 実装チェックリスト

実行環境に関する注記

  • OPENAI_API_KEY は環境変数として既に投入済みなので .env には記載せず、そのまま利用してください。
  • LM Studio / Ollama は 192.168.11.16 上で稼働しています。
    • LM Studio: openai/gpt-oss-20b モデルを OpenAI 互換エンドポイント経由で利用可能。
    • Ollama: gpt-oss:20b モデルを利用可能。

トレース切替

Agent では hefa_core::Tracer を差し替えることでトレースの保存先を切り替えられます。

use hefa_core::{StdoutTracer, SqliteTracer};

let tracer = StdoutTracer::default(); // 開発時は標準出力
// もしくは永続化
let tracer = SqliteTracer::new("trace.db")?;
let agent = agent.with_tracer(std::sync::Arc::new(tracer));

SqliteTracer には list_recent_spans / list_events があり、SQLite 上に保存された span / event の検索が可能です。

LLM クライアント

hefa_core::LLMClient はプロバイダ種別に応じて自動で OpenAI Responses API / OpenAI 互換 ChatCompletion API を呼び分けます。以下は「エンジニアの日報からリリースノートのドラフトを作る」例です。

use hefa_core::{
    llm::StructuredOutput, Agent, AgentConfig, ProviderKind, Tool, ToolError, ToolResult,
};
use async_trait::async_trait;
use serde_json::{json, Value};

/// Tool used when LLM asks for metadata to enrich the release note.
/// LLM が「リリースノートの下書きを作って」と要求した際に呼ばれる Hook。
struct ReleaseNoteTool;

#[async_trait]
impl Tool for ReleaseNoteTool {
    fn name(&self) -> &'static str {
        "release_note"
    }

    fn json_schema(&self) -> Value {
        json!({
            "type": "object",
            "properties": {
                "feature": { "type": "string" },
                "impact": { "type": "string" }
            },
            "required": ["feature", "impact"]
        })
    }

    async fn call(&self, args: Value) -> Result<ToolResult, ToolError> {
        let feature = args
            .get("feature")
            .and_then(Value::as_str)
            .ok_or_else(|| ToolError::InvalidInput("missing feature".into()))?;
        let impact = args
            .get("impact")
            .and_then(Value::as_str)
            .ok_or_else(|| ToolError::InvalidInput("missing impact".into()))?;
        Ok(ToolResult {
            content: json!({ "draft": format!("Feature: {feature} — Impact: {impact}") }),
        })
    }
}

let structured_output = StructuredOutput::new(json!({
    "type": "object",
    "properties": {
        "summary": { "type": "string" }
    }
}));

let mut agent = Agent::new(AgentConfig {
    instruction: "You are a release-note assistant. Respond in 1 sentence.".into(),
    provider: ProviderKind::OpenAi,
    model: "gpt-4o-mini".into(),
    structured_output: Some(structured_output),
    tools: vec![Box::new(ReleaseNoteTool)],
})?;

let prompt = "Update: Added offline search with 50% faster indexing.";
let result = agent.invoke(prompt).await?;
println!("Release note: {}", result.response.content);

出力例:

Release note: OK — Feature: Added offline search with 50% faster indexing.

チュートリアル / Examples

  1. ステップ1 – LLM 選択 & Hello
    まずは Provider とモデルを決め、最小構成の Agent で “Hello” を返す例 (examples/basic_agent.rs) を実行します。

    cargo run --example basic_agent
    
  2. ステップ2 – Tool 追加
    examples/tool_agent.rs では LLM の tool_calls を処理する Hook を登録し、ReleaseNoteTool で外部ロジックを呼び出す流れを体験します。

    cargo run --example tool_agent
    
  3. ステップ3 – 構造化出力
    JSON Schema を指定して LLM の最終回答を構造化する例は examples/structured_agent.rs で確認できます。README で紹介した StructuredOutput::from_type::<T>() も併用してください。

    cargo run --example structured_agent
    
  4. ステップ4 – トレース
    examples/trace_agent.rsSqliteTracer を使って span / event を保存し、list_recent_spans で属性フィルタ(例: instruction に “release” が含まれる)をかけて検索する例です。Tracer には start_trace / start_child_span / record_event が用意されており、Agent はこれらを内部で呼び出します。

    cargo run --example trace_agent
    
  5. ステップ5 – Release Note Agent (統合)
    examples/release_note.rs で、Tool + 構造化出力 + トレースの統合例を確認できます。

    cargo run --example release_note
    

ライブ接続テスト

OpenAI / LM Studio / Ollama に接続する実機テストは tests/live_llm.rs にあります。 以下の環境変数をセットして個別に実行してください。

HEFA_LIVE_OPENAI=1 cargo test live_openai_responses
HEFA_LIVE_LMSTUDIO=1 LMSTUDIO_API_BASE=http://192.168.11.16:1234/v1 cargo test live_lmstudio_chat
HEFA_LIVE_OLLAMA=1 OLLAMA_API_BASE=http://192.168.11.16:11434 cargo test live_ollama_chat

構造化出力と schemars 連携

Feature schema を有効にすると、schemars::JsonSchema を derive した型から StructuredOutput::from_type::<T>() で JSON Schema を生成できます。LLM へ構造化出力を要求する際に役立ちます。

cargo add schemars --features derive
cargo test --features schema
use hefa_core::llm::StructuredOutput;
use schemars::JsonSchema;
use serde::Serialize;

#[derive(Serialize, JsonSchema)]
struct MyAnswer {
    summary: String,
    tags: Vec<String>,
}

let output = StructuredOutput::from_type::<MyAnswer>();

ライセンス

TBD

Commit count: 0

cargo fmt