flow問い合わせ v1examples/inquiry/temporal/inquiry.ja.flow · dandori doc
お客さまの問い合わせの種類を判断のモデルが選び、その確信度も返す。エージェントは問い合わせを読んで注文番号と要点を取り出し、種類も読む。判断のモデルが種類に十分な確信を持てないときは、エージェントが読んだ種類を使う。受け持つ窓口と最初の返事までの時間は規則が決め、返事の下書きは別のエージェントが書き、窓口のシステムに起票する。選ぶことは判断のモデルが、読むことと書くことはエージェントが、決めることは規則が受け持つ(選ぶのと読むのは会社が自分で動かしているモデル、書くのは Claude)。Temporal 向けの版:判断とエージェントは生成したアクティビティで、種類は System One の API(TypeSafe の Jev の API)を話すサーバーに尋ね(`url`。この例では会社の Ollama)、読み取りは Open Responses を話すサーバーに(`url`。同じ Ollama)、下書きはワーカーが持つ鍵で Claude に送る。規則はワークフローと同じワーカーでローカルアクティビティとして動き、その結果はマーカーとして履歴に残る。起票は自分で書くアクティビティ
flow| 行 | 呼び出し | 呼ぶもの | リトライ | タイムアウト | 失敗したとき |
|---|---|---|---|---|---|
| 66 | 読み = 読み取る(…) | agent · gpt-oss:20b · http://ollama.internal:11434/v1 | 10 秒おきに 2 回(failure・timeout) | 1 分 | timeout・failure → 67 行目 |
| 68 | 手作業 = 起票する(…) | 自分で書くタスク・key | 5 秒おきに 2 回(failure・timeout) | — | timeout・failure → ワークフローが失敗する |
| 71 | 種類 = 種類を選ぶ(…) | jev · nimble:9b-q4_K_M · http://ollama.internal:11434/v1 · confidence 0.8 else 迷い | 1 秒おきに 2 回(failure・timeout) | 10 秒 | 迷い・timeout・failure → 72 行目 |
| 73 | 判定 = 振り分け(…) | 規則 問い合わせの振り分け.rule(Temporal ではローカルアクティビティ) | 1 秒後と 2 秒後の 2 回(failure・timeout) | 10 秒 | timeout・failure → ワークフローが失敗する |
| 78 | 下書き = 下書きする(…) | agent claude · claude-sonnet-5 | — | 1 分 | timeout・failure → 79 行目 |
| 80 | 票 = 起票する(…) | 自分で書くタスク・key | 5 秒おきに 2 回(failure・timeout) | — | timeout・failure → ワークフローが失敗する |
| 行 | 終わり方 |
|---|---|
| 69 | succeed チケットID = 手作業.チケットID, 窓口 = 総合 |
| 81 | succeed チケットID = 票.チケットID, 窓口 = 判定.窓口 |
ステップを選ぶと、そこについて検査で分かったことが出ます。左のシナリオを選ぶと、その実行が通るところが光ります。ステップの横の数は、その実行が通った回数です。
問い合わせ v1お客さまの問い合わせの種類を判断のモデルが選び、その確信度も返す。エージェントは問い合わせを読んで注文番号と要点を取り出し、種類も読む。判断のモデルが種類に十分な確信を持てないときは、エージェントが読んだ種類を使う。受け持つ窓口と最初の返事までの時間は規則が決め、返事の下書きは別のエージェントが書き、窓口のシステムに起票する。選ぶことは判断のモデルが、読むことと書くことはエージェントが、決めることは規則が受け持つ(選ぶのと読むのは会社が自分で動かしているモデル、書くのは Claude)。Temporal 向けの版:判断とエージェントは生成したアクティビティで、種類は System One の API(TypeSafe の Jev の API)を話すサーバーに尋ね(`url`。この例では会社の Ollama)、読み取りは Open Responses を話すサーバーに(`url`。同じ Ollama)、下書きはワーカーが持つ鍵で Claude に送る。規則はワークフローと同じワーカーでローカルアクティビティとして動き、その結果はマーカーとして履歴に残る。起票は自分で書くアクティビティ
問い合わせ: 問い合わせチケットID: string・窓口: 振り分け.窓口examples/inquiry/temporal/inquiry.ja.flow読み = 読み取る(…) 66 行目66 let 読み = 読み取る(本文: 問い合わせ.本文) 67 on failure =>
agent · gpt-oss:20b · http://ollama.internal:11434/v1timeout・failure → 67 行目43 # 会社が自分で動かしている Ollama のモデルが、Open Responses を通して本文を読む。読み取りの 44 # Schema が、答えを規則の種類のどれかに縛る。 45 task 読み取る(本文: string) -> 読み取り 46 agent "お客さまからの問い合わせの本文を読み、種類を一つ選び、注文番号が書かれていれば取り出し、要点を一文にまとめてください。注文番号が書かれていなければ null にします。" 47 model "gpt-oss:20b" 48 effort low 49 url "http://ollama.internal:11434/v1" 50 plaintext "モデルのサーバーにはクラスターのネットワークの中だけで届き、そこはサービスメッシュが暗号化する" 51 timeout 60 seconds 52 retry 2 times every 10 seconds
手作業 = 起票する(…) 68 行目 68 let 手作業 = 起票する(問い合わせID: 問い合わせ.id, 窓口: 総合, 期限: 24, 件名: "読み取れなかった問い合わせ", 本文: 問い合わせ.本文, 下書き: none)
keytimeout・failure → ワークフローが失敗する60 # 起票は、窓口のシステムのクライアントライブラリを使って、自分で書くコードで行う。 61 task 起票する(問い合わせID: string, 窓口: 振り分け.窓口, 期限: duration[h], 件名: string, 本文: string, 下書き: string?) -> 起票 62 key 63 retry 2 times every 5 seconds
succeed チケットID = 手作業.チケットID, 窓口 = 総合 69 行目 69 succeed チケットID = 手作業.チケットID, 窓口 = 総合
種類 = 種類を選ぶ(…) 71 行目71 let 種類 = 種類を選ぶ(本文: 問い合わせ.本文) 72 on 迷い, failure => let 種類 = 読み.種類
jev · nimble:9b-q4_K_M · http://ollama.internal:11434/v1 · confidence 0.8 else 迷い迷い・timeout・failure → 72 行目27 # 会社が自分で動かしている Ollama の判断のモデルが、System One の API で、規則の種類のどれかを 28 # それぞれの意味を見て選び、その確信度も返す。モデルはタグまで書き、確信度の意味の違う別のモデルに 29 # 移らないようにする。 30 task 種類を選ぶ(本文: string) -> 振り分け.種類 31 jev "この問い合わせの種類はどれか" 32 返品 "商品を返したい、交換したい" 33 配送 "荷物が遅れている、届かない、壊れていた、どこにあるか知りたい" 34 請求 "請求、支払い、返金のこと" 35 その他 "上のどれでもない" 36 model "nimble:9b-q4_K_M" 37 url "http://ollama.internal:11434/v1" 38 plaintext "モデルのサーバーにはクラスターのネットワークの中だけで届き、そこはサービスメッシュが暗号化する" 39 confidence 0.8 else 迷い 40 timeout 10 seconds 41 retry 2 times every 1 second
let 種類 = 読み.種類 72 行目 72 on 迷い, failure => let 種類 = 読み.種類
判定 = 振り分け(…) 73 行目 73 let 判定 = 振り分け(種類: 種類, 会員: 問い合わせ.会員)
問い合わせの振り分け.rule(Temporal ではローカルアクティビティ)timeout・failure → ワークフローが失敗する4 use rule 振り分け from "../rules/問い合わせの振り分け.rule" 5 local
let 件名 = "{種類}の問い合わせ" 74 行目 74 let 件名 = "{種類}の問い合わせ"
match 読み.注文ID 75 行目75 match 読み.注文ID 76 some 注文ID => let 件名 = "{種類}の問い合わせ(注文 {注文ID})" 77 none => pass
let 件名 = "{種類}の問い合わせ(注文 {注文ID})" 76 行目 76 some 注文ID => let 件名 = "{種類}の問い合わせ(注文 {注文ID})"
下書き = 下書きする(…) 78 行目78 let 下書き = 下書きする(種類: 種類, 要点: 読み.要点, 注文ID: 読み.注文ID, 期限: 判定.期限) 79 on failure => let 下書き: string? = none
agent claude · claude-sonnet-5timeout・failure → 79 行目54 task 下書きする(種類: 振り分け.種類, 要点: string, 注文ID: string?, 期限: duration[h]) -> string 55 agent claude "問い合わせへの最初の返事を、丁寧な日本語で三文以内に下書きしてください。`期限` は返事をするまでの時間の数です。約束できないことは書きません。" 56 model "claude-sonnet-5" 57 effort medium 58 timeout 60 seconds
let 下書き = none 79 行目 79 on failure => let 下書き: string? = none
票 = 起票する(…) 80 行目 80 let 票 = 起票する(問い合わせID: 問い合わせ.id, 窓口: 判定.窓口, 期限: 判定.期限, 件名: 件名, 本文: 問い合わせ.本文, 下書き: 下書き)
keytimeout・failure → ワークフローが失敗する60 # 起票は、窓口のシステムのクライアントライブラリを使って、自分で書くコードで行う。 61 task 起票する(問い合わせID: string, 窓口: 振り分け.窓口, 期限: duration[h], 件名: string, 本文: string, 下書き: string?) -> 起票 62 key 63 retry 2 times every 5 seconds
succeed チケットID = 票.チケットID, 窓口 = 判定.窓口 81 行目 81 succeed チケットID = 票.チケットID, 窓口 = 判定.窓口
終わり(成功)flow が最後まで走り、ワークフローは成功します。
読み = 読み取る(…) ok種類 = 種類を選ぶ(…) ok判定 = 振り分け(…) oklet 件名 = "{種類}の問い合わせ"match 読み.注文ID → none下書き = 下書きする(…) ok票 = 起票する(…) oksucceed チケットID = 票.チケットID, 窓口 = 判定.窓口読み = 読み取る(…) failure failure failure → on failure手作業 = 起票する(…) oksucceed チケットID = 手作業.チケットID, 窓口 = 総合読み = 読み取る(…) failure failure failure → on failure手作業 = 起票する(…) failure failure failure → ここでは処理しない読み = 読み取る(…) failure ok種類 = 種類を選ぶ(…) ok → on 迷い, failurelet 種類 = 読み.種類判定 = 振り分け(…) failure failure failure → ここでは処理しない読み = 読み取る(…) ok読み = 読み取る(…) ok種類 = 種類を選ぶ(…) ok → on 迷い, failurelet 種類 = 読み.種類判定 = 振り分け(…) ok読み = 読み取る(…) ok種類 = 種類を選ぶ(…) failure ok判定 = 振り分け(…) ok読み = 読み取る(…) ok種類 = 種類を選ぶ(…) ok読み = 読み取る(…) ok種類 = 種類を選ぶ(…) ok判定 = 振り分け(…) oklet 件名 = "{種類}の問い合わせ"match 読み.注文ID → some 注文IDlet 件名 = "{種類}の問い合わせ(注文 {注文ID})"下書き = 下書きする(…) failure → on failurelet 下書き = none票 = 起票する(…) failure failure failure → ここでは処理しない読み = 読み取る(…) ok種類 = 種類を選ぶ(…) ok判定 = 振り分け(…) oklet 件名 = "{種類}の問い合わせ"match 読み.注文ID → none下書き = 下書きする(…) failure → on failurelet 下書き = none票 = 起票する(…) failure oksucceed チケットID = 票.チケットID, 窓口 = 判定.窓口読み = 読み取る(…) ok種類 = 種類を選ぶ(…) ok判定 = 振り分け(…) oklet 件名 = "{種類}の問い合わせ"match 読み.注文ID → none下書き = 下書きする(…) ok読み = 読み取る(…) ok種類 = 種類を選ぶ(…) ok判定 = 振り分け(…) oklet 件名 = "{種類}の問い合わせ"match 読み.注文ID → none下書き = 下書きする(…) ok票 = 起票する(…) ok読み = 読み取る(…) failure failure failure → on failure手作業 = 起票する(…) failure oksucceed チケットID = 手作業.チケットID, 窓口 = 総合読み = 読み取る(…) failure failure failure → on failure手作業 = 起票する(…) ok