I use a language bridge where it saves time and remove it when it costs more than it saves, without disturbing the code that depends on it. These are thin wrappers around a third-party Python model; the judgment is in where the boundary sat and when it moved.
An embedding model inside a Rust function
In FAFO Core and Function Forge the research and memory functions are Rust, and the embedding model they needed was easiest to reach through a Python library. I used PyO3 to bring the model into the Rust function and keep everything else native. The rest of the function stays ordinary Rust on the substrate, queue-driven and controllable like any other.
The research steps that consumed these embeddings, a validator for candidate question-and-answer pairs and a near-neighbour rebalancing step, were ported from an earlier Python pipeline into typed Rust functions, with this wrapper as the only Python left in them.
Moving the model behind a service boundary
In FAFOHive I used the same pattern first and later moved off it. The memory service ran the embedding model in process through PyO3, then through a GPU subprocess. Every search feature depended on that path.
PyO3 bought speed of delivery; once its cost showed, I moved the model behind a network boundary.
GPU memory and process stability both suffered.
No caller changed.
The graph tools that sit beside the embeddings are in A code explainer that is not allowed to invent.